package com.zxy.ziems.server.energy.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.esotericsoftware.minlog.Log;
import com.zxy.btp.mybatis.base.BaseEntity;
import com.zxy.ziems.server.board.constant.BoardConstant;
import com.zxy.ziems.server.budget.pojo.entity.BudgetDefEntity;
import com.zxy.ziems.server.budget.pojo.entity.BudgetValueEntity;
import com.zxy.ziems.server.budget.service.BudgetDefService;
import com.zxy.ziems.server.budget.service.BudgetValueService;
import com.zxy.ziems.server.classify.pojo.entity.Classify;
import com.zxy.ziems.server.classify.pojo.entity.ClassifyDeviceProperty;
import com.zxy.ziems.server.classify.service.ClassifyDevicePropertyService;
import com.zxy.ziems.server.classify.service.ClassifyService;
import com.zxy.ziems.server.constant.ClassifyCountType;
import com.zxy.ziems.server.constant.DateType;
import com.zxy.ziems.server.constant.PointDataType;
import com.zxy.ziems.server.constant.enums.CalculateTypeEnum;
import com.zxy.ziems.server.device.pojo.entity.DeviceEntity;
import com.zxy.ziems.server.device.service.DeviceService;
import com.zxy.ziems.server.domain.ClassifyPointRel;
import com.zxy.ziems.server.domain.PointData;
import com.zxy.ziems.server.dto.DataQueryDto;
import com.zxy.ziems.server.dto.DateDto;
import com.zxy.ziems.server.dto.DeviceMeasureDateGroupDto;
import com.zxy.ziems.server.energy.enums.EnergyDataTypeEnum;
import com.zxy.ziems.server.energy.pojo.dto.ClassifyDeviceEleDTO;
import com.zxy.ziems.server.energy.pojo.dto.DeviceMeasureDateDTO;
import com.zxy.ziems.server.energy.service.DataChartService;
import com.zxy.ziems.server.energy.service.DeviceMeasureDataService;
import com.zxy.ziems.server.energy.service.DeviceTypeDataService;
import com.zxy.ziems.server.energy.util.WetDryExcelExportUtil;
import com.zxy.ziems.server.mapper.ClassifyPointRelMapper;
import com.zxy.ziems.server.mapper.PointDataMapper;
import com.zxy.ziems.server.statistics.pojo.param.BudgetQueryParam;
import com.zxy.ziems.server.utils.AssertUtil;
import com.zxy.ziems.server.utils.DateUtils;
import com.zxy.ziems.server.utils.QueryUtils;
import com.zxy.ziems.server.vo.*;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

import static com.zxy.ziems.server.utils.DateUtils.YMD_PATTERN;

/**
 * @ClassName DataChartServiceImpl
 * @Description
 * @Author 邓伟
 * @Date 2023/12/6 11:00
 * @Version 1.0
 */
@Service
public class DataChartServiceImpl implements DataChartService {

    @Autowired
    private ClassifyService classifyService;
    @Autowired
    private ClassifyDevicePropertyService classifyDevicePropertyService;
    @Autowired
    private DeviceMeasureDataService deviceMeasureDataService;
    @Autowired
    private ClassifyPointRelMapper classifyPointRelMapper;
    @Autowired
    private PointDataMapper pointDataMapper;
    @Autowired
    private DeviceService deviceService;
    @Autowired
    private DeviceTypeDataService deviceTypeDataService;
    @Autowired
    private BudgetDefService budgetDefService;
    @Autowired
    private BudgetValueService budgetValueService;

    // 筛选电类型数据，并过滤2度以下数值
    String ELECTRICITY = "电";
    int THRESHOLD = 2;


    @Override
    public ChartVo lastCycleDataCompare(DataQueryDto dataQueryDto) {
        //根据查询条件计算起止时间
        String queryType = dataQueryDto.getQueryType();
        DateDto dateDto = DateUtils.dateQueryConvert(queryType, dataQueryDto.getStartDay(), dataQueryDto.getEndDay(), true);
        Classify classify = classifyService.getById(dataQueryDto.getClassifyId());
        //构建x轴
        List<LocalDateTime> list = DateUtils.dateToList(queryType, dateDto.getStartDay(), dateDto.getEndDay());
        //判断是否需要返回空值
        Integer dataObtainType = classify.getDataObtainType();
        ChartVo chartVo = buildCompareEmpty(queryType, list);
//        if (!checkIsNeedReturnEmpty(queryType, dataObtainType)) {
//            return chartVo;
//        }

        List<ClassifyDeviceProperty> devicePropertyList = getClassifyDeviceProperties(dataQueryDto.getClassifyId());

        Set<String> deviceIdSet = devicePropertyList.stream().map(ClassifyDeviceProperty::getDeviceId).collect(Collectors.toSet());
        if (devicePropertyList.isEmpty()) {
            return chartVo;
        }
        ClassifyDeviceProperty classifyDeviceProperty = devicePropertyList.get(0);
        String dataTypeId = classifyDeviceProperty.getDataTypeId();

        List<DeviceMeasureDateDTO> thisDateDtos = classifySum(classify.getClassifyId(), queryType, dateDto.getStartDay(), dateDto.getEndDay(), classify, devicePropertyList);
        List<DeviceMeasureDateDTO> lastDateDtos = classifySum(classify.getClassifyId(), queryType, dateDto.getLastStartDay(), dateDto.getLastEndDay(), classify, devicePropertyList);

//        List<DeviceMeasureDateDTO> thisDateDtos = getDeviceMeasureDateTypeDtos(queryType, dateDto.getStartDay(), dateDto.getEndDay(), classify, deviceIdSet, dataTypeId);
//        List<DeviceMeasureDateDTO> lastDateDtos = getDeviceMeasureDateTypeDtos(queryType, dateDto.getLastStartDay(), dateDto.getLastEndDay(), classify, deviceIdSet, dataTypeId);

        if (CollectionUtil.isEmpty(thisDateDtos) && CollectionUtil.isEmpty(lastDateDtos)) {
            return chartVo;
        }

//        multipleProcess(thisDateDtos, classifyDeviceProperty.getMultiple());
//        multipleProcess(lastDateDtos, classifyDeviceProperty.getMultiple());


        // 查询数据
        Map<String, List<DeviceMeasureDateDTO>> thisMap = buildDataByDataType(thisDateDtos);
        Map<String, List<DeviceMeasureDateDTO>> lastMap = buildDataByDataType(lastDateDtos);
        //按照查询类型和数据类型对数据时间进行处理，并分组，将数据处理为x轴需要的格式进行匹配
        ChartYAxisVo thisChartYAxisVo = new ChartYAxisVo();
        thisChartYAxisVo.setName("本周期");

        thisChartYAxisVo.setStack("this");
        List<BigDecimal> thisYValueList = new ArrayList<>();

        ChartYAxisVo lastChartYAxisVo = new ChartYAxisVo();
        lastChartYAxisVo.setName("上周期");

        lastChartYAxisVo.setStack("last");
        List<BigDecimal> lastYValueList = new ArrayList<>();
        Map<String, String> dateTimeMap = DateUtils.getThisAndLastDateMap(queryType, dateDto);
        for (String dateTimeStr : chartVo.getXAxisList()) {
            //本周期数据
            setYVal(thisMap, thisYValueList, dateTimeStr);
            //上周期数据
            String lastDateTimeStr = dateTimeMap.get(dateTimeStr);
            if (StrUtil.isEmpty(lastDateTimeStr)) {
                lastYValueList.add(BigDecimal.ZERO);
            } else {
                setYVal(lastMap, lastYValueList, lastDateTimeStr);
            }


        }
        thisChartYAxisVo.setData(thisYValueList);
        lastChartYAxisVo.setData(lastYValueList);
        chartVo.setYAxisList(List.of(lastChartYAxisVo, thisChartYAxisVo));
        return chartVo;
    }

    @Override
    public ChartVo thisCycleData(DataQueryDto dataQueryDto) {
        //根据查询条件计算起止时间
        String queryType = dataQueryDto.getQueryType();
        DateDto dateDto = DateUtils.dateQueryConvert(queryType, dataQueryDto.getStartDay(), dataQueryDto.getEndDay(), false);
        Classify classify = classifyService.getById(dataQueryDto.getClassifyId());
        //构建x轴
        List<LocalDateTime> list = DateUtils.dateToList(queryType, dateDto.getStartDay(), dateDto.getEndDay());
        //判断是否需要返回空值
        Integer dataObtainType = classify.getDataObtainType();
        ChartVo chartVo = buildEmpty(queryType, list, classify.getClassifyName());

        List<ClassifyDeviceProperty> devicePropertyList = getClassifyDeviceProperties(dataQueryDto.getClassifyId());


        List<DeviceMeasureDateDTO> dateDtos = classifySum(classify.getClassifyId(), queryType, dateDto.getStartDay(), dateDto.getEndDay(), classify, devicePropertyList);
//        tree(classify.getClassifyId(), queryType, dateDto.getStartDay(), dateDto.getEndDay(), classify, devicePropertyList, dateDtos);
//
//
//        if (CollectionUtil.isEmpty(dateDtos)) {
//            return chartVo;
//        }
//
//
//        // 根据时间分组
//        Map<String, List<DeviceMeasureDateDTO>> map1 = dateDtos.stream().collect(Collectors.groupingBy(m -> m.getDayStr()));
//
//        // 各分组求和
//        List<DeviceMeasureDateDTO> deviceMeasureDateDTOList1 = extracted(map1);

//        multipleProcess(dateDtos, classifyDeviceProperty.getMultiple());

        //按照查询类型和数据类型对数据时间进行处理，并分组，将数据处理为x轴需要的格式进行匹配
        Map<String, List<DeviceMeasureDateDTO>> map = buildDataByDataType(dateDtos);
        ChartYAxisVo chartYAxisVo = new ChartYAxisVo();
        chartYAxisVo.setName(classify.getClassifyName());

        List<BigDecimal> yValueList = new ArrayList<>();
        for (String dateTimeStr : chartVo.getXAxisList()) {
            setYVal(map, yValueList, dateTimeStr, dataQueryDto.getDataType());
        }
        chartYAxisVo.setData(yValueList);
        chartVo.setYAxisList(List.of(chartYAxisVo));
        return chartVo;
    }


    @Override
    public ChartCodeVo thisCycleDataAndCode(DataQueryDto dataQueryDto) {
        //根据查询条件计算起止时间
        String queryType = dataQueryDto.getQueryType();
        DateDto dateDto = DateUtils.dateQueryConvert(queryType, dataQueryDto.getStartDay(), dataQueryDto.getEndDay(), false);
        Classify classify = classifyService.getById(dataQueryDto.getClassifyId());
        //构建x轴
        List<LocalDateTime> list = DateUtils.dateToList(queryType, dateDto.getStartDay(), dateDto.getEndDay());
        //判断是否需要返回空值
        Integer dataObtainType = classify.getDataObtainType();
        ChartVo chartVo = buildEmpty(queryType, list, classify.getClassifyName());

        List<ClassifyDeviceProperty> devicePropertyList = getClassifyDeviceProperties(dataQueryDto.getClassifyId());


        List<DeviceMeasureDateDTO> dateDtos = classifySum(classify.getClassifyId(), queryType, dateDto.getStartDay(), dateDto.getEndDay(), classify, devicePropertyList);
//        tree(classify.getClassifyId(), queryType, dateDto.getStartDay(), dateDto.getEndDay(), classify, devicePropertyList, dateDtos);
//
//
//        if (CollectionUtil.isEmpty(dateDtos)) {
//            return chartVo;
//        }
//
//
//        // 根据时间分组
//        Map<String, List<DeviceMeasureDateDTO>> map1 = dateDtos.stream().collect(Collectors.groupingBy(m -> m.getDayStr()));
//
//        // 各分组求和
//        List<DeviceMeasureDateDTO> deviceMeasureDateDTOList1 = extracted(map1);

//        multipleProcess(dateDtos, classifyDeviceProperty.getMultiple());

        //按照查询类型和数据类型对数据时间进行处理，并分组，将数据处理为x轴需要的格式进行匹配
        Map<String, List<DeviceMeasureDateDTO>> map = buildDataByDataType(dateDtos);


        // 用量
        ChartYAxisVo chartYAxisVo = new ChartYAxisVo();
        chartYAxisVo.setName(classify.getClassifyName());
        List<BigDecimal> yValueList = new ArrayList<>();
        for (String dateTimeStr : chartVo.getXAxisList()) {
            setYVal(map, yValueList, dateTimeStr, EnergyDataTypeEnum.ENERGY.getCode());
        }
        chartYAxisVo.setData(yValueList);
        chartVo.setYAxisList(List.of(chartYAxisVo));

        // 花费
        ChartYAxisVo chartCodeYAxisVo = new ChartYAxisVo();
        chartCodeYAxisVo.setName(classify.getClassifyName());
        List<BigDecimal> codeyValueList = new ArrayList<>();
        for (String dateTimeStr : chartVo.getXAxisList()) {
            setYVal(map, codeyValueList, dateTimeStr, EnergyDataTypeEnum.CODE.getCode());
        }
        chartCodeYAxisVo.setData(codeyValueList);
        chartVo.setYAxisList(List.of(chartCodeYAxisVo));


        ChartCodeVo chartCodeVo = ChartCodeVo.builder()
                .xAxisList(chartVo.getXAxisList())
                .yAxisList(List.of(chartYAxisVo))
                .codeyAxisList(List.of(chartCodeYAxisVo))
                .build();

        return chartCodeVo;
    }


    /**
     * 获取给分类下所有数据
     *
     * @param classifyId
     * @param queryType
     * @param startDay
     * @param endDay
     * @return
     */
//    @Override
//    public List<DeviceMeasureDateDTO> classifyAllById(String classifyId, String queryType, String startDay, String endDay) {
//        List<DeviceMeasureDateDTO> dateDtos = new ArrayList<>();
//        List<ClassifyDeviceProperty> devicePropertyList = getClassifyDeviceProperties(classifyId);
//        Classify classify = classifyService.getById(classifyId);
//
//
//        tree(classifyId, queryType, startDay, endDay, classify, devicePropertyList, dateDtos);
//
//
//        if (CollectionUtil.isEmpty(dateDtos)) {
//            return dateDtos;
//        }
//
//
//        // 根据时间分组
//        Map<String, List<DeviceMeasureDateDTO>> map1 = dateDtos.stream().collect(Collectors.groupingBy(m -> m.getDayStr()));
//
//        // 各分组求和
//        return extracted(map1);
//    }

    private List<DeviceMeasureDateDTO> classifySum(String classifyId, String queryType, String startDay, String endDay, Classify classify, List<ClassifyDeviceProperty> devicePropertyList) {
        List<DeviceMeasureDateDTO> dateDtos = new ArrayList<>();
        tree(classifyId, queryType, startDay, endDay, classify, devicePropertyList, dateDtos);


        if (CollectionUtil.isEmpty(dateDtos)) {
            return dateDtos;
        }


        // 根据时间分组
        Map<String, List<DeviceMeasureDateDTO>> map1 = dateDtos.stream().collect(Collectors.groupingBy(m -> m.getDayStr()));

        // 各分组求和
        return extracted(map1);
    }

    private Map<String, List<DeviceMeasureDateDTO>> classifySumEle(String classifyId, String queryType, String startDay, String endDay, Classify classify, List<ClassifyDeviceProperty> devicePropertyList) {
        List<ClassifyDeviceEleDTO> dateDtos = new ArrayList<>();
        treeEle(classifyId, queryType, startDay, endDay, classify, devicePropertyList, dateDtos);


        if (CollectionUtil.isEmpty(dateDtos)) {
            return new HashMap<>();
        }


        // 根据时间分组
        Map<String, List<ClassifyDeviceEleDTO>> map1 = dateDtos.stream().collect(Collectors.groupingBy(m -> m.getTag()));

        Map<String, List<DeviceMeasureDateDTO>> map = new HashMap<>();

        for (String tag : map1.keySet()) {
            List<ClassifyDeviceEleDTO> classifyDeviceEleDTOList = map1.get(tag);
            Map<String, List<ClassifyDeviceEleDTO>> collect = classifyDeviceEleDTOList.stream().collect(Collectors.groupingBy(m -> m.getDayStr()));

            List<DeviceMeasureDateDTO> deviceMeasureDateDTOS = extractedEle(collect);
            map.put(tag, deviceMeasureDateDTOS);
        }

        // 各分组求和
        return map;
    }


    private void tree(String parentClassifyId, String queryType, String start, String end, Classify classifyParent, List<ClassifyDeviceProperty> devicePropertyList, List<DeviceMeasureDateDTO> dateDtos) {
        List<Classify> classifyList = classifyService.getChildrenClassify(parentClassifyId);

        Set<String> deviceIdSet = devicePropertyList.stream().filter(m -> m.getClassifyId().equals(parentClassifyId)).map(ClassifyDeviceProperty::getDeviceId).collect(Collectors.toSet());
        if (!deviceIdSet.isEmpty()) {
            ClassifyDeviceProperty classifyDeviceProperty = devicePropertyList.get(0);
            String dataTypeId = classifyDeviceProperty.getDataTypeId();

            List<DeviceMeasureDateDTO> dateDtoSons = getDeviceMeasureDateTypeDtos(queryType, start, end, classifyParent, deviceIdSet, dataTypeId, classifyDeviceProperty.getCalculateType());
            dateDtoSons = dateDtoSons.stream().map(m -> {
                m.setStatistic(m.getStatistic().setScale(2, RoundingMode.HALF_UP).multiply(classifyParent.getMultiple()));
                return m;
            }).collect(Collectors.toList());
            dateDtos.addAll(dateDtoSons);
        }


        if (!CollectionUtil.isEmpty(classifyList)) {
            for (Classify classify : classifyList) {
                classify.setMultiple(classify.getMultiple().multiply(classifyParent.getMultiple()));
                tree(classify.getClassifyId(), queryType, start, end, classify, devicePropertyList, dateDtos);
            }
        }
    }

    private void treeEle(String parentClassifyId, String queryType, String start, String end, Classify classifyParent, List<ClassifyDeviceProperty> devicePropertyList, List<ClassifyDeviceEleDTO> dateDtos) {
        List<Classify> classifyList = classifyService.getChildrenClassify(parentClassifyId);

        Set<String> deviceIdSet = devicePropertyList.stream().filter(m -> m.getClassifyId().equals(parentClassifyId)).map(ClassifyDeviceProperty::getDeviceId).collect(Collectors.toSet());
        if (!deviceIdSet.isEmpty()) {
            ClassifyDeviceProperty classifyDeviceProperty = devicePropertyList.get(0);
            String dataTypeId = classifyDeviceProperty.getDataTypeId();

            // 获取分类信息
            List<Classify> classifyAllList = classifyService.classifyListByClassifyId(parentClassifyId);
            List<String> classifyIds = classifyAllList.stream().map(Classify::getClassifyId).collect(Collectors.toList());

            List<ClassifyDeviceEleDTO> dateDtoSons = deviceMeasureDataService.getDeviceTypeEle(queryType, DateUtils.checkFormat(start, YMD_PATTERN),
                    DateUtils.checkFormat(end, YMD_PATTERN), deviceIdSet, dataTypeId, classifyIds);
            dateDtoSons = dateDtoSons.stream().map(m -> {
                m.setStatistic(m.getStatistic().setScale(2, RoundingMode.HALF_UP).multiply(classifyParent.getMultiple()));
                return m;
            }).collect(Collectors.toList());
            dateDtos.addAll(dateDtoSons);
        }


        if (!CollectionUtil.isEmpty(classifyList)) {
            for (Classify classify : classifyList) {
                classify.setMultiple(classify.getMultiple().multiply(classifyParent.getMultiple()));
                treeEle(classify.getClassifyId(), queryType, start, end, classify, devicePropertyList, dateDtos);
            }
        }
    }


    /**
     * 获取设备采集统计集
     *
     * @param queryType
     * @param startDay
     * @param endDay
     * @param classify
     * @param deviceIdSet
     * @param dataTypeId
     * @return
     */
    private List<DeviceMeasureDateDTO> getDeviceMeasureDateDtos(String queryType, String startDay, String endDay, Classify classify, Set<String> deviceIdSet, String dataTypeId) {
        List<DeviceMeasureDateDTO> dateDtos = new ArrayList<>();
//        if (classify.getCountType().equals(ClassifyCountType.POINT_COUNT)) {
//            // 如果是平均，获取平均的统计
//            dateDtos = deviceMeasureDataService.getAvg(queryType, DateUtils.checkFormat(startDay, YMD_PATTERN),
//                    DateUtils.checkFormat(endDay, YMD_PATTERN), deviceIdSet, dataTypeId);
//        } else if (classify.getCountType().equals(ClassifyCountType.CLASSIFY_COUNT)) {
//            // 如果是求和，获取求和统计
//            dateDtos = deviceMeasureDataService.getSum(queryType, DateUtils.checkFormat(startDay, YMD_PATTERN),
//                    DateUtils.checkFormat(endDay, YMD_PATTERN), deviceIdSet, dataTypeId);
//        }
        // 如果是求和，获取求和统计
        dateDtos = deviceMeasureDataService.getSum(queryType, DateUtils.checkFormat(startDay, YMD_PATTERN),
                DateUtils.checkFormat(endDay, YMD_PATTERN), deviceIdSet, dataTypeId);
        return dateDtos;
    }


    private List<DeviceMeasureDateDTO> getDeviceMeasureDateTypeSumAndAvgDtos(String queryType, String startDay, String endDay, Classify classify, Set<String> deviceIdSet, String dataTypeId) {
        List<DeviceMeasureDateDTO> dateDtos = new ArrayList<>();

//        if (classify.getCountType().equals(ClassifyCountType.POINT_COUNT)) {
//            // 如果是平均，获取平均的统计
//            dateDtos = deviceTypeDataService.avgTree(classify.getClassifyId(), queryType, DateUtils.checkFormat(startDay, YMD_PATTERN),
//                    DateUtils.checkFormat(endDay, YMD_PATTERN), deviceIdSet, dataTypeId);
//        } else if (classify.getCountType().equals(ClassifyCountType.CLASSIFY_COUNT)) {
//            // 如果是求和，获取求和统计
//            dateDtos = deviceTypeDataService.sumTree(classify.getClassifyId(), queryType, DateUtils.checkFormat(startDay, YMD_PATTERN),
//                    DateUtils.checkFormat(endDay, YMD_PATTERN), deviceIdSet, dataTypeId);
//        }
        // 如果是求和，获取求和统计
        dateDtos = deviceTypeDataService.sumTree(classify.getClassifyId(), queryType, DateUtils.checkFormat(startDay, YMD_PATTERN),
                DateUtils.checkFormat(endDay, YMD_PATTERN), deviceIdSet, dataTypeId);
        return dateDtos;
    }


    /**
     * 前提条件（所有设备dataTypeId是一致的）
     *
     * @param queryType
     * @param startDay
     * @param endDay
     * @param classify
     * @param deviceIdSet
     * @param dataTypeId
     * @return
     */
    private List<DeviceMeasureDateDTO> getDeviceMeasureDateTypeDtos(String queryType, String startDay, String endDay, Classify classify, Set<String> deviceIdSet, String dataTypeId, Integer calculateType) {
        List<DeviceMeasureDateDTO> dateDtos = new ArrayList<>();

        if (calculateType.equals(CalculateTypeEnum.MEASURE.getCode())) {
            // 如果是实时值，获取平均的统计
            dateDtos = deviceTypeDataService.avgTree(classify.getClassifyId(), queryType, DateUtils.checkFormat(startDay, YMD_PATTERN),
                    DateUtils.checkFormat(endDay, YMD_PATTERN), deviceIdSet, dataTypeId);
        } else if (calculateType.equals(CalculateTypeEnum.INCREMENT.getCode())) {
            // 如果是增量值，获取求和统计
            dateDtos = deviceTypeDataService.sumTree(classify.getClassifyId(), queryType, DateUtils.checkFormat(startDay, YMD_PATTERN),
                    DateUtils.checkFormat(endDay, YMD_PATTERN), deviceIdSet, dataTypeId);
        } else if (calculateType.equals(CalculateTypeEnum.MEASURE_INCREMENT.getCode())) {
            // 如果是实时增量值（采集值是按小时统计的值），天统计则会使用实际值求和
            dateDtos = deviceTypeDataService.sumTreeReal(classify.getClassifyId(), queryType, DateUtils.checkFormat(startDay, YMD_PATTERN),
                    DateUtils.checkFormat(endDay, YMD_PATTERN), deviceIdSet, dataTypeId);
        }

        return dateDtos;
    }

    /**
     * 各分组求和
     *
     * @param map
     * @return
     */
    private List<DeviceMeasureDateDTO> extracted(Map<String, List<DeviceMeasureDateDTO>> map) {
        List<DeviceMeasureDateDTO> dateDtos = new ArrayList<>();
        for (String s : map.keySet()) {
            List<DeviceMeasureDateDTO> deviceMeasureDateGroupDtoList = map.get(s);
            BigDecimal bigDecimal = new BigDecimal(0);
            BigDecimal bigCost = new BigDecimal(0);
            for (DeviceMeasureDateDTO deviceMeasureDateGroupDto : deviceMeasureDateGroupDtoList) {
                bigDecimal = bigDecimal.add(deviceMeasureDateGroupDto.getStatistic());
                bigCost = bigCost.add(deviceMeasureDateGroupDto.getCost());
            }
            DeviceMeasureDateDTO deviceMeasureDateDto = new DeviceMeasureDateDTO();
            deviceMeasureDateDto.setDayStr(s);
            deviceMeasureDateDto.setStatistic(bigDecimal);
            deviceMeasureDateDto.setCost(bigCost);
            dateDtos.add(deviceMeasureDateDto);
        }
        return dateDtos;
    }

    /**
     * 各分组求和
     *
     * @param map
     * @return
     */
    private List<DeviceMeasureDateDTO> extractedEle(Map<String, List<ClassifyDeviceEleDTO>> map) {
        List<DeviceMeasureDateDTO> dateDtos = new ArrayList<>();
        for (String s : map.keySet()) {
            List<ClassifyDeviceEleDTO> deviceMeasureDateGroupDtoList = map.get(s);
            BigDecimal bigDecimal = new BigDecimal(0);
            for (ClassifyDeviceEleDTO deviceMeasureDateGroupDto : deviceMeasureDateGroupDtoList) {
                bigDecimal = bigDecimal.add(deviceMeasureDateGroupDto.getStatistic());
            }
            DeviceMeasureDateDTO deviceMeasureDateDto = new DeviceMeasureDateDTO();
            deviceMeasureDateDto.setDayStr(s);
            deviceMeasureDateDto.setStatistic(bigDecimal);
            dateDtos.add(deviceMeasureDateDto);
        }
        return dateDtos;
    }

    /**
     * 根据分类ID获取设备分类属性关系集
     *
     * @param classifyId
     * @return
     */
    @Override
    public List<ClassifyDeviceProperty> getClassifyDeviceProperties(String classifyId) {
        //根据分类id查询所有的下级分类id
        List<String> classifyIdList = classifyService.getClassifyId(classifyId);
        // 根据分类查询设备属性关系
        return getClassifyDeviceProperties(classifyIdList);
    }

    @Override
    public Map<String, BigDecimal> getCurClassifySum(DataQueryDto dataQueryDto) {
        Map<String, BigDecimal> result = new HashMap<>();

        //根据查询条件计算起止时间
        String queryType = dataQueryDto.getQueryType();
        DateDto dateDto = DateUtils.dateQueryConvert(queryType, dataQueryDto.getStartDay(), dataQueryDto.getEndDay(), false);
        // 获取类型信息
        Classify classify = classifyService.getById(dataQueryDto.getClassifyId());
        List<Classify> classifyList = new ArrayList<>();
        classifyList.add(classify);
        for (Classify query : classifyList) {

            List<ClassifyDeviceProperty> devicePropertyList = getClassifyDeviceProperties(query.getClassifyId());

            if (CollectionUtil.isEmpty(devicePropertyList)) {
                continue;
            }

            Set<String> deviceIdSet = devicePropertyList.stream().map(ClassifyDeviceProperty::getDeviceId).collect(Collectors.toSet());
            ClassifyDeviceProperty classifyDeviceProperty = devicePropertyList.get(0);
            String dataTypeId = classifyDeviceProperty.getDataTypeId();
            Integer calculateType = classifyDeviceProperty.getCalculateType();

            List<DeviceMeasureDateDTO> dateDtos = getDeviceMeasureDateTypeDtos(queryType, dateDto.getStartDay(), dateDto.getEndDay(),
                    classify, deviceIdSet, dataTypeId, calculateType);

            if (CollectionUtil.isNotEmpty(dateDtos)) {
                    BigDecimal bigDecimal = dateDtos.stream().map(DeviceMeasureDateDTO::getStatistic)
                            .reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_UP);
//                    Log.info("getCurClassifySumDEBUG:"+query.getClassifyId()+"->"+bigDecimal);
                    result.put(query.getClassifyId(), bigDecimal);
            }else{
                result.put(query.getClassifyId(), BigDecimal.ZERO);
            }

        }
        return result;
    }

    /**
     * 计算环比
     * @param dataQueryDto
     * @return
     */
    @Override
    public ChartVo dataChain(DataQueryDto dataQueryDto) {
        //根据查询条件计算起止时间
        String queryType = dataQueryDto.getQueryType();
        DateDto dateDto = DateUtils.dateQueryConvert(queryType, dataQueryDto.getStartDay(), dataQueryDto.getEndDay(), true);
        Classify classify = classifyService.getById(dataQueryDto.getClassifyId());
        //构建x轴
        List<LocalDateTime> listCur = DateUtils.dateToList(queryType, dateDto.getStartDay(), dateDto.getEndDay());
        List<LocalDateTime> listPre = DateUtils.dateToList(queryType, dateDto.getLastStartDay(), dateDto.getLastEndDay());
        //判断是否需要返回空值
//        Integer dataObtainType = classify.getDataObtainType();
        ChartVo chartVoMerge = new ChartVo();

        ChartVo chartVoCur = buildEmpty(queryType, listCur, classify.getClassifyName());
        ChartVo chartVoPre = buildEmpty(queryType, listPre, classify.getClassifyName());

        List<ClassifyDeviceProperty> devicePropertyList = getClassifyDeviceProperties(dataQueryDto.getClassifyId());


        // 当前周期
        List<DeviceMeasureDateDTO> dateDtosCur = classifySum(classify.getClassifyId(), queryType, dateDto.getStartDay(), dateDto.getEndDay(), classify, devicePropertyList);

        // 上一周期
        List<DeviceMeasureDateDTO> dateDtosPre = classifySum(classify.getClassifyId(), queryType, dateDto.getLastStartDay(), dateDto.getLastEndDay(), classify, devicePropertyList);

        //按照查询类型和数据类型对数据时间进行处理，并分组，将数据处理为x轴需要的格式进行匹配
        Map<String, List<DeviceMeasureDateDTO>> mapCur = buildDataByDataType(dateDtosCur);
        Map<String, List<DeviceMeasureDateDTO>> mapPre = buildDataByDataType(dateDtosPre);


        // 当前周期
        ChartYAxisVo chartYAxisVoCur = new ChartYAxisVo();
        chartYAxisVoCur.setName(classify.getClassifyName());
        List<BigDecimal> yValueListCur = new ArrayList<>();
        for (String dateTimeStr : chartVoCur.getXAxisList()) {
            setYVal(mapCur, yValueListCur, dateTimeStr, dataQueryDto.getDataType());
        }
        chartYAxisVoCur.setData(yValueListCur);
        chartVoCur.setYAxisList(List.of(chartYAxisVoCur));


        // 上一周期
        ChartYAxisVo chartYAxisVoPre = new ChartYAxisVo();
        chartYAxisVoPre.setName(classify.getClassifyName());
        List<BigDecimal> yValueListPre = new ArrayList<>();
        for (String dateTimeStr : chartVoPre.getXAxisList()) {
            setYVal(mapPre, yValueListPre, dateTimeStr, dataQueryDto.getDataType());
        }
        chartYAxisVoPre.setData(yValueListPre);
        chartVoPre.setYAxisList(List.of(chartYAxisVoPre));
        // 重新配置x轴
        List<String> xAxisList = new ArrayList<>();
        for(int i = 1; i < chartVoPre.getXAxisList().size(); i++){
            xAxisList.add(String.valueOf(i));
        }
        chartVoMerge.setXAxisList(xAxisList);


        return chartVoCur;
    }

    /**
     * 根据分类ID获取设备分类属性关系集
     *
     * @param classifyIdList
     * @return
     */
    private List<ClassifyDeviceProperty> getClassifyDeviceProperties(List<String> classifyIdList) {
        QueryWrapper<ClassifyDeviceProperty> queryClass = new QueryWrapper<>();
        queryClass.lambda().in(ClassifyDeviceProperty::getClassifyId, classifyIdList)
                .eq(BaseEntity::getDeleteStatus, 0);
        List<ClassifyDeviceProperty> devicePropertyList = classifyDevicePropertyService.list(queryClass);
        return devicePropertyList;
    }

    @Override
    public List<PieChartVo> thisCycleDataPie(DataQueryDto dataQueryDto) {
        Integer dataType = dataQueryDto.getDataType();
        //根据查询条件计算起止时间
        String queryType = dataQueryDto.getQueryType();
        DateDto dateDto = DateUtils.dateQueryConvert(queryType, dataQueryDto.getStartDay(), dataQueryDto.getEndDay(), false);
        Classify classify = classifyService.getById(dataQueryDto.getClassifyId());
        List<Classify> classifyList = new ArrayList<>();
        if (classify.getCountType() == ClassifyCountType.POINT_COUNT) {
            classifyList.add(classify);
        } else {
            classifyList = classifyService.getChildrenClassify(dataQueryDto.getClassifyId());
        }
        //判断是否需要返回空值
        Integer dataObtainType = classify.getDataObtainType();
        List<PieChartVo> pieChartVoList = buildPieChart(classifyList);
        //查询每个次级分类下的点位编码
        Map<String, PieChartVo> pieChartVoMap = pieChartVoList.stream().collect(Collectors.toMap(PieChartVo::getClassifyId, v1 -> v1));
        for (Classify query : classifyList) {

            List<ClassifyDeviceProperty> devicePropertyList = getClassifyDeviceProperties(query.getClassifyId());

            if (CollectionUtil.isEmpty(devicePropertyList)) {
                continue;
            }

            Set<String> deviceIdSet = devicePropertyList.stream().map(ClassifyDeviceProperty::getDeviceId).collect(Collectors.toSet());
            ClassifyDeviceProperty classifyDeviceProperty = devicePropertyList.get(0);
            String dataTypeId = classifyDeviceProperty.getDataTypeId();
            Integer calculateType = classifyDeviceProperty.getCalculateType();

            List<DeviceMeasureDateDTO> dateDtos = getDeviceMeasureDateTypeDtos(queryType, dateDto.getStartDay(), dateDto.getEndDay(),
                    classify, deviceIdSet, dataTypeId, calculateType);

            if (CollectionUtil.isNotEmpty(dateDtos)) {

//                multipleProcess(dateDtos, classifyDeviceProperty.getMultiple());

                PieChartVo pieChartVo = pieChartVoMap.get(query.getClassifyId());
                if (query.getCountType().equals(ClassifyCountType.CLASSIFY_COUNT)) {
                    if (dataType == null || dataType.equals(EnergyDataTypeEnum.ENERGY.getCode())) {
                        pieChartVo.setValue(dateDtos.stream().map(DeviceMeasureDateDTO::getStatistic)
                                .reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_UP));
                    } else if (dataType.equals(EnergyDataTypeEnum.CODE.getCode())) {
                        pieChartVo.setValue(dateDtos.stream().map(DeviceMeasureDateDTO::getCost)
                                .reduce(BigDecimal.ZERO, BigDecimal::add).setScale(2, RoundingMode.HALF_UP));
                    }
                } else {
                    BigDecimal average = BigDecimal.ZERO;
                    if (dataType == null || dataType.equals(EnergyDataTypeEnum.ENERGY.getCode())) {
                        average = dateDtos.stream()
                                .map(DeviceMeasureDateDTO::getStatistic) // 如果流中已经是BigDecimal，则这一步可以省略
                                .reduce(BigDecimal.ZERO, BigDecimal::add)
                                .setScale(2, BigDecimal.ROUND_HALF_UP);
                    } else if (dataType.equals(EnergyDataTypeEnum.CODE.getCode())) {
                        average = dateDtos.stream()
                                .map(DeviceMeasureDateDTO::getCost) // 如果流中已经是BigDecimal，则这一步可以省略
                                .reduce(BigDecimal.ZERO, BigDecimal::add)
                                .setScale(2, BigDecimal.ROUND_HALF_UP);
                    }
//                            .divide(new BigDecimal(dateDtos.size()), 2, BigDecimal.ROUND_HALF_UP);
                    pieChartVo.setValue(average);
                }
            }

        }
        return new ArrayList<>(pieChartVoMap.values());
    }

    @Override
    public ChartVo compareBarChart(DataQueryDto dataQueryDto) {
        //根据查询条件计算起止时间
        String queryType = dataQueryDto.getQueryType();
        DateDto dateDto = DateUtils.dateQueryConvert(queryType, dataQueryDto.getStartDay(), dataQueryDto.getEndDay(), false);
        //构建x轴
        List<LocalDateTime> list = DateUtils.dateToList(queryType, dateDto.getStartDay(), dateDto.getEndDay());
        ChartVo chartVo = new ChartVo();
        chartVo.setXAxisList(DateUtils.xAxisConvert(queryType, list));
        List<ChartYAxisVo> chartYList = new ArrayList<>();
        List<String> queryIdList = dataQueryDto.getClassifyIdList();
        for (String classifyId : queryIdList) {
            Classify classify = classifyService.getById(classifyId);
            List<ClassifyDeviceProperty> devicePropertyList = getClassifyDeviceProperties(classifyId);

            //判断是否需要返回空值
            if (CollectionUtil.isEmpty(devicePropertyList)) {
                chartYList.add(buildEmptyChartYAxisVo(list.size(), classify, "bar"));
                continue;
            }
            Set<String> deviceIdSet = devicePropertyList.stream().map(ClassifyDeviceProperty::getDeviceId).collect(Collectors.toSet());
            ClassifyDeviceProperty classifyDeviceProperty = devicePropertyList.get(0);
            // 设备参数ID
            String dataTypeId = classifyDeviceProperty.getDataTypeId();
            // 计算方式 1.实时值，2.增量值 3.辅助计算值
            Integer calculateType = classifyDeviceProperty.getCalculateType();

            List<DeviceMeasureDateDTO> dateDtos = getDeviceMeasureDateTypeDtos(queryType, dateDto.getStartDay(), dateDto.getEndDay(),
                    classify, deviceIdSet, dataTypeId, calculateType);

            //根据点位数据时间进行分组汇总数据
            if (CollectionUtil.isEmpty(dateDtos)) {
                chartYList.add(buildEmptyChartYAxisVo(list.size(), classify, "bar"));
                continue;
            }

//            multipleProcess(dateDtos, classifyDeviceProperty.getMultiple());

            //按照查询类型和数据类型对数据时间进行处理，并分组，将数据处理为x轴需要的格式进行匹配
            Map<String, List<DeviceMeasureDateDTO>> thisMap = buildDataByDataType(dateDtos);
            List<BigDecimal> yValueList = new ArrayList<>();
            for (String dateTimeStr : chartVo.getXAxisList()) {
                //本周期数据
                setYVal(thisMap, yValueList, dateTimeStr, dataQueryDto.getDataType());
            }
            // 过滤，电量10以下的展示为0，yValueList中小于10的赋值0
            if (classify.getEnergyType().equals(ELECTRICITY)) {
                for (int i = 0; i < yValueList.size(); i++) {
                    BigDecimal value = yValueList.get(i);
                    if (value != null && value.compareTo(new BigDecimal(THRESHOLD)) < 0) {
                        yValueList.set(i, new BigDecimal(0));
                    }
                }
            }
            ChartYAxisVo chartYAxisVo = new ChartYAxisVo();
            chartYAxisVo.setName(classify.getClassifyName());
            chartYAxisVo.setData(yValueList);

            chartYAxisVo.setStack(classifyId);
            chartYList.add(chartYAxisVo);
        }
        chartVo.setYAxisList(chartYList);
        return chartVo;
    }

    @Override
    public void exportChildData(HttpServletResponse response, DataQueryDto dataQueryDto) {
        //根据查询条件计算起止时间
        String queryType = dataQueryDto.getQueryType();
        DateDto dateDto = DateUtils.dateQueryConvert(queryType, dataQueryDto.getStartDay(), dataQueryDto.getEndDay(), false);
        //构建x轴
        List<LocalDateTime> list = DateUtils.dateToList(queryType, dateDto.getStartDay(), dateDto.getEndDay());
        ChartVo chartVo = new ChartVo();
        chartVo.setXAxisList(DateUtils.xAxisConvert(queryType, list));
        List<ChartYAxisVo> chartYList = new ArrayList<>();
        List<String> queryIdList = dataQueryDto.getClassifyIdList();


        List<DeviceMeasureDateGroupDto> deviceMeasureDateGroupDtoAllList = new ArrayList<>();
        List<Classify> classifyList = new ArrayList<>();
        List<DeviceEntity> deviceEntityAllList = new ArrayList<>();
        for (String classifyId : queryIdList) {
            Classify classify = classifyService.getById(classifyId);
            List<ClassifyDeviceProperty> devicePropertyList = getClassifyDeviceProperties(classifyId);
            classifyList.add(classify);


            //判断是否需要返回空值
            if (CollectionUtil.isEmpty(devicePropertyList)) {
                chartYList.add(buildEmptyChartYAxisVo(list.size(), classify, "bar"));
                continue;
            }
            Set<String> deviceIdSet = devicePropertyList.stream().map(ClassifyDeviceProperty::getDeviceId).collect(Collectors.toSet());
            List<DeviceEntity> deviceEntityList = deviceService.listByIdListAndDelete(deviceIdSet);
            deviceEntityAllList.addAll(deviceEntityList);

            ClassifyDeviceProperty classifyDeviceProperty = devicePropertyList.get(0);
            String dataTypeId = classifyDeviceProperty.getDataTypeId();


            // 获取所有采集值
            List<DeviceMeasureDateGroupDto> dateDtos = getMeasureDateTypeDtos(dateDto.getStartDay(), dateDto.getEndDay(),
                    classify.getClassifyId(), deviceIdSet, dataTypeId);

            Map<String, List<DeviceMeasureDateGroupDto>> deviceMeasureDateGroupDtoMap = dateDtos.stream().collect(Collectors.groupingBy(m -> m.getDayStr()));
            for (String o : deviceMeasureDateGroupDtoMap.keySet()) {
                List<DeviceMeasureDateGroupDto> deviceMeasureDateGroupDtoList = deviceMeasureDateGroupDtoMap.get(o);

                BigDecimal statistic = deviceMeasureDateGroupDtoList.stream()
                        .map(DeviceMeasureDateGroupDto::getStatistic)
                        .reduce(BigDecimal.ZERO, BigDecimal::add)
                        .divide(BigDecimal.valueOf(deviceMeasureDateGroupDtoList.size()), 2, BigDecimal.ROUND_HALF_UP);

                DeviceMeasureDateGroupDto deviceMeasureDateGroupDto = new DeviceMeasureDateGroupDto();
                deviceMeasureDateGroupDto.setStatistic(statistic);
                deviceMeasureDateGroupDto.setDayStr(o);
                deviceMeasureDateGroupDto.setDeviceId(classifyId);
                deviceMeasureDateGroupDtoAllList.add(deviceMeasureDateGroupDto);
                deviceMeasureDateGroupDtoAllList.addAll(deviceMeasureDateGroupDtoList);
            }

        }

        WetDryExcelExportUtil wetDryExcelExportUtil = new WetDryExcelExportUtil();
        wetDryExcelExportUtil.complexFillWithTable1(response, dataQueryDto.getItemName(), classifyList, deviceEntityAllList, deviceMeasureDateGroupDtoAllList);
    }

    private List<DeviceMeasureDateGroupDto> getMeasureDateTypeDtos(String startDay, String endDay, String classifyId, Set<String> deviceIdSet, String dataTypeId) {

        return deviceMeasureDataService.listDeviceHour(startDay, endDay, classifyId, deviceIdSet, dataTypeId);
    }

    @Override
    public ChartVo compareBarChartEle(DataQueryDto dataQueryDto) {
        //根据查询条件计算起止时间
        String queryType = dataQueryDto.getQueryType();
        DateDto dateDto = DateUtils.dateQueryConvert(queryType, dataQueryDto.getStartDay(), dataQueryDto.getEndDay(), false);
        Classify classify = classifyService.getById(dataQueryDto.getClassifyId());
        //构建x轴
        List<LocalDateTime> list = DateUtils.dateToList(queryType, dateDto.getStartDay(), dateDto.getEndDay());

        ChartVo chartVo = buildEmpty(queryType, list, classify.getClassifyName());

        List<ClassifyDeviceProperty> devicePropertyList = getClassifyDeviceProperties(dataQueryDto.getClassifyId());


        Map<String, List<DeviceMeasureDateDTO>> map = classifySumEle(classify.getClassifyId(), queryType, dateDto.getStartDay(), dateDto.getEndDay(), classify, devicePropertyList);
        List<ChartYAxisVo> chartYList = new ArrayList<>();
        for (String tag : map.keySet()) {
            List<DeviceMeasureDateDTO> deviceMeasureDateDTOS = map.get(tag);
            //判断是否需要返回空值
            if (CollectionUtil.isEmpty(devicePropertyList)) {
                chartYList.add(buildEmptyChartYAxisVo(list.size(), classify, "bar"));
                continue;
            }

            //根据点位数据时间进行分组汇总数据
            if (CollectionUtil.isEmpty(deviceMeasureDateDTOS)) {
                chartYList.add(buildEmptyChartYAxisVo(list.size(), classify, "bar"));
                continue;
            }

            //按照查询类型和数据类型对数据时间进行处理，并分组，将数据处理为x轴需要的格式进行匹配
            Map<String, List<DeviceMeasureDateDTO>> thisMap = buildDataByDataType(deviceMeasureDateDTOS);
            List<BigDecimal> yValueList = new ArrayList<>();
            for (String dateTimeStr : chartVo.getXAxisList()) {
                //本周期数据
                setYVal(thisMap, yValueList, dateTimeStr, dataQueryDto.getDataType());
            }
            ChartYAxisVo chartYAxisVo = new ChartYAxisVo();
            chartYAxisVo.setName(tag);
            chartYAxisVo.setData(yValueList);
            chartYList.add(chartYAxisVo);
        }

        chartVo.setYAxisList(chartYList);
        return chartVo;
    }

    @Override
    public ReportVo compareChartReport(DataQueryDto dataQueryDto) {
        //根据查询条件计算起止时间
        String queryType = dataQueryDto.getQueryType();
        DateDto dateDto = DateUtils.dateQueryConvert(queryType, dataQueryDto.getStartDay(), dataQueryDto.getEndDay(), false);
        List<LocalDateTime> list = DateUtils.dateToList(queryType, dateDto.getStartDay(), dateDto.getEndDay());
        ReportVo reportVo = new ReportVo();
        List<String> dateTimeList = DateUtils.xAxisConvert(queryType, list);
        reportVo.setDateTimeList(dateTimeList);
        List<ReportDataVo> reportDataVoList = new ArrayList<>();
        List<String> queryIdList = dataQueryDto.getClassifyIdList();
        for (String classifyId : queryIdList) {
            Classify classify = classifyService.getById(classifyId);
            List<ClassifyDeviceProperty> devicePropertyList = getClassifyDeviceProperties(classifyId);

            //判断是否需要返回空值
            if (CollectionUtil.isEmpty(devicePropertyList)) {
                reportDataVoList.add(buildEmptyReportDataVo(dateTimeList, classify, ""));
                continue;
            }

            Set<String> deviceIdSet = devicePropertyList.stream().map(ClassifyDeviceProperty::getDeviceId).collect(Collectors.toSet());
            ClassifyDeviceProperty classifyDeviceProperty = devicePropertyList.get(0);
            String dataTypeId = classifyDeviceProperty.getDataTypeId();
            Integer calculateType = classifyDeviceProperty.getCalculateType();

            List<DeviceMeasureDateDTO> dateDtos = getDeviceMeasureDateTypeDtos(queryType, dateDto.getStartDay(), dateDto.getEndDay(),
                    classify, deviceIdSet, dataTypeId, calculateType);

            //根据点位数据时间进行分组汇总数据
            if (CollectionUtil.isEmpty(dateDtos)) {
                reportDataVoList.add(buildEmptyReportDataVo(dateTimeList, classify, ""));
                continue;
            }

//            multipleProcess(dateDtos, classifyDeviceProperty.getMultiple());

            //按照查询类型和数据类型对数据时间进行处理，并分组，将数据处理为x轴需要的格式进行匹配
            Map<String, List<DeviceMeasureDateDTO>> thisMap = buildDataByDataType(dateDtos);
            Map<String, Object> dataMap = new HashMap<>();
            BigDecimal total = BigDecimal.ZERO;
            for (String dateTimeStr : dateTimeList) {
                //本周期数据
                BigDecimal data = setMapValue(thisMap, dataMap, dateTimeStr, classify.getCountType());
                total = total.add(data);
            }
            //计算合计
            ReportDataVo reportDataVo = new ReportDataVo();
            reportDataVo.setClassifyName(classify.getClassifyName());
            reportDataVo.setTotalCount(total.setScale(2, RoundingMode.HALF_UP));
            reportDataVo.setDataMap(dataMap);
            reportDataVoList.add(reportDataVo);
        }
        reportVo.setDataVoList(reportDataVoList);
        return reportVo;
    }


//    /**
//     * 设备集倍率处理
//     * @param dateDtos
//     * @param multiple
//     */
//    private void multipleProcess(List<DeviceMeasureDateDto> dateDtos, BigDecimal multiple) {
//        if (CollectionUtil.isEmpty(dateDtos)) {
//            return;
//        }
//        dateDtos.forEach(m -> m.setStatistic(m.getStatistic().multiply(multiple)));
//    }

    /**
     * 设备，分类分开，参考deviceCompareLineChart
     *
     * @param dataQueryDto
     * @return
     */
    @Override
    @Deprecated
    public ChartVo pointCompareLineChart(DataQueryDto dataQueryDto) {
        //根据查询条件计算起止时间
        String queryType = dataQueryDto.getQueryType();
        DateDto dateDto = DateUtils.dateQueryConvert(queryType, dataQueryDto.getStartDay(), dataQueryDto.getEndDay(), false);
        //构建x轴
        List<LocalDateTime> list = DateUtils.dateToList(queryType, dateDto.getStartDay(), dateDto.getEndDay());
        ChartVo chartVo = new ChartVo();
        chartVo.setXAxisList(DateUtils.xAxisConvert(queryType, list));
        List<ChartYAxisVo> chartYList = new ArrayList<>();
        List<String> queryIdList = dataQueryDto.getClassifyIdList();
        List<String> classifyIdList = classifyService.getByIdList(queryIdList);
        if (CollectionUtil.isEmpty(classifyIdList)) {
            classifyIdList = queryIdList;
        }

        //根据分类id查询关联的点位信息
        QueryWrapper<ClassifyPointRel> queryPoint = new QueryWrapper<>();
        queryPoint.lambda().in(ClassifyPointRel::getClassifyId, classifyIdList).select(ClassifyPointRel::getPointCode, ClassifyPointRel::getClassifyId, ClassifyPointRel::getDataObtainType);
        List<ClassifyPointRel> pointRelList = classifyPointRelMapper.selectList(queryPoint);
        if (CollectionUtil.isEmpty(pointRelList)) {
            return chartVo;
        }
        //循环点位信息，判断是否有点位不符合查询条件
        Map<Integer, List<ClassifyPointRel>> relMap = pointRelList.stream().collect(Collectors.groupingBy(ClassifyPointRel::getDataObtainType));
        for (Integer type : relMap.keySet()) {
            List<ClassifyPointRel> relPointList = relMap.get(type);
            if (!checkIsNeedReturnEmpty(queryType, type)) {

                for (ClassifyPointRel classifyPointRel : relPointList) {
                    chartYList.add(buildEmptyChartYAxisVo(list.size(), classifyPointRel, "line"));
                }
                continue;
            }
            //查询数据
            List<String> pointCodeList = relPointList.stream().map(ClassifyPointRel::getPointCode).toList();
            List<PointData> pointDataList = getPointDataList(dateDto.getStartDay(), dateDto.getEndDay(), type, pointCodeList);
            if (CollectionUtil.isEmpty(pointDataList)) {
                for (ClassifyPointRel classifyPointRel : relPointList) {
                    chartYList.add(buildEmptyChartYAxisVo(list.size(), classifyPointRel, "line"));
                }
                continue;
            }
            //将数据处理为map结构map<点位编码，Map<X轴时间格式，数据值>>
            Map<String, Map<String, BigDecimal>> thisMap = buildPointDataByDataType(pointDataList, queryType);
            for (ClassifyPointRel classifyPointRel : relPointList) {
                String pointCode = classifyPointRel.getPointCode();
                Map<String, BigDecimal> pointDataMap = thisMap.get(pointCode);
                if (CollectionUtil.isEmpty(pointDataMap)) {
                    chartYList.add(buildEmptyChartYAxisVo(list.size(), classifyPointRel, "line"));
                    continue;
                }
                List<BigDecimal> yValueList = new ArrayList<>();
                for (String dateTimeStr : chartVo.getXAxisList()) {
                    if (pointDataMap.containsKey(dateTimeStr)) {
                        yValueList.add(pointDataMap.get(dateTimeStr).setScale(2, RoundingMode.HALF_UP));
                    } else {
                        yValueList.add(BigDecimal.ZERO);
                    }
                }
                ChartYAxisVo chartYAxisVo = new ChartYAxisVo();
                chartYAxisVo.setName(classifyPointRel.getPointCode());
                chartYAxisVo.setData(yValueList);

                chartYList.add(chartYAxisVo);
            }
            chartVo.setYAxisList(chartYList);
        }

        return chartVo;
    }

    @Override
    public ChartVo deviceCompareLineChart(DataQueryDto dataQueryDto) {

        //根据查询条件计算起止时间
        String queryType = dataQueryDto.getQueryType();
        DateDto dateDto = DateUtils.dateQueryConvert(queryType, dataQueryDto.getStartDay(), dataQueryDto.getEndDay(), false);
        //构建x轴
        List<LocalDateTime> list = DateUtils.dateToList(queryType, dateDto.getStartDay(), dateDto.getEndDay());
        ChartVo chartVo = new ChartVo();
        chartVo.setXAxisList(DateUtils.xAxisConvert(queryType, list));

        List<ChartYAxisVo> chartYList = new ArrayList<>();
        // 获取分类设备
        List<DataQueryDto.ClassDevice> deviceList = dataQueryDto.getDeviceList();

        deviceList.forEach(classDevice -> {
            List<ClassifyDeviceProperty> property = classifyDevicePropertyService.getByClassifyIdAndDeviceId(classDevice.getClassifyId(), classDevice.getDeviceId());
            DeviceEntity device = deviceService.getById(classDevice.getDeviceId());
            if (CollectionUtil.isEmpty(property)) {
                chartYList.add(buildEmptyChartYAxisVo(list.size(), device, "line"));
                return;
            }
            ClassifyDeviceProperty classifyDeviceProperty = property.get(0);
            Classify classify = classifyService.getById(classDevice.getClassifyId());
//            List<DeviceMeasureDateDTO> deviceMeasureDateDTOS = getDeviceMeasureDateDtos(queryType, dateDto.getStartDay(), dateDto.getEndDay(), classify, Set.of(classDevice.getDeviceId()), classifyDeviceProperty.getDataTypeId());
            List<DeviceMeasureDateDTO> deviceMeasureDateDTOS = getDeviceMeasureDateTypeDtos(queryType, dateDto.getStartDay(), dateDto.getEndDay(), classify, Set.of(classDevice.getDeviceId()), classifyDeviceProperty.getDataTypeId(), classifyDeviceProperty.getCalculateType());
            if (CollectionUtil.isEmpty(deviceMeasureDateDTOS)) {
                chartYList.add(buildEmptyChartYAxisVo(list.size(), device, "line"));
                return;
            }

//            multipleProcess(deviceMeasureDateDtos, classifyDeviceProperty.getMultiple());

            //将数据处理为map结构map<点位编码，Map<X轴时间格式，数据值>>
            Map<String, Map<String, BigDecimal>> thisMap = buildDeviceDataByDataType(deviceMeasureDateDTOS, device.getCode());
            Map<String, BigDecimal> pointDataMap = thisMap.get(device.getCode());
            List<BigDecimal> yValueList = new ArrayList<>();
            BigDecimal total = BigDecimal.ZERO;
            for (String dateTimeStr : chartVo.getXAxisList()) {
                if (pointDataMap.containsKey(dateTimeStr)) {
                    BigDecimal bigDecimal = pointDataMap.get(dateTimeStr).setScale(2, RoundingMode.HALF_UP);
                    yValueList.add(bigDecimal);
                    total = total.add(bigDecimal);
                } else {
                    yValueList.add(BigDecimal.ZERO);
                }
            }
            ChartYAxisVo chartYAxisVo = new ChartYAxisVo();
            chartYAxisVo.setName(device.getName());
            chartYAxisVo.setCode(device.getCode());
            chartYAxisVo.setName(device.getName());
            chartYAxisVo.setData(yValueList);

            chartYAxisVo.setTotalCount(total);

            chartYList.add(chartYAxisVo);
        });
        chartVo.setYAxisList(chartYList);

        return chartVo;
    }

    private Map<String, Map<String, BigDecimal>> buildPointDataByDataType(List<PointData> pointDataList, String queryType) {
        Map<String, Map<String, BigDecimal>> map = new HashMap<>();
        if (CollectionUtil.isEmpty(pointDataList)) {
            return map;
        }
        for (PointData pointData : pointDataList) {
            String pointCode = pointData.getPointCode();
            String dateStr = DateUtils.getDateStrByQueryType(queryType, pointData.getDataTime());
            if (map.containsKey(pointCode)) {
                Map<String, BigDecimal> pointDataMap = map.get(pointCode);
                if (pointDataMap.containsKey(dateStr)) {
                    BigDecimal data = pointDataMap.get(dateStr);
                    data = data.add(pointData.getDataValue());
                    pointDataMap.put(dateStr, data);
                } else {
                    pointDataMap.put(dateStr, pointData.getDataValue());
                }
            } else {
                Map<String, BigDecimal> pointDataMap = new HashMap<>();
                pointDataMap.put(dateStr, pointData.getDataValue());
                map.put(pointCode, pointDataMap);
            }
        }
        return map;

    }

    private Map<String, Map<String, BigDecimal>> buildDeviceDataByDataType(List<DeviceMeasureDateDTO> pointDataList, String deviceCode) {
        Map<String, Map<String, BigDecimal>> map = new HashMap<>();
        if (CollectionUtil.isEmpty(pointDataList)) {
            return map;
        }
        for (DeviceMeasureDateDTO pointData : pointDataList) {
            String dateStr = pointData.getDayStr();
            if (map.containsKey(deviceCode)) {
                Map<String, BigDecimal> pointDataMap = map.get(deviceCode);
                if (pointDataMap.containsKey(dateStr)) {
                    BigDecimal data = pointDataMap.get(dateStr);
                    data = data.add(pointData.getStatistic());
                    pointDataMap.put(dateStr, data);
                } else {
                    pointDataMap.put(dateStr, pointData.getStatistic());
                }
            } else {
                Map<String, BigDecimal> pointDataMap = new HashMap<>();
                pointDataMap.put(dateStr, pointData.getStatistic());
                map.put(deviceCode, pointDataMap);
            }
        }
        return map;

    }

    /**
     * 本周期环比数据报表
     * 设备，分类分开，参考deviceCompareLineReport
     *
     * @param dataQueryDto
     * @return
     */
    @Deprecated
    @Override
    public ReportVo pointCompareLineReport(DataQueryDto dataQueryDto) {
        //根据查询条件计算起止时间
        String queryType = dataQueryDto.getQueryType();
        DateDto dateDto = DateUtils.dateQueryConvert(queryType, dataQueryDto.getStartDay(), dataQueryDto.getEndDay(), true);
        //构建x轴
        List<LocalDateTime> list = DateUtils.dateToList(queryType, dateDto.getStartDay(), dateDto.getEndDay());
        ReportVo reportVo = new ReportVo();
        List<String> dateTimeList = DateUtils.xAxisConvert(queryType, list);
        reportVo.setDateTimeList(dateTimeList);
        List<ReportDataVo> reportDataVoList = new ArrayList<>();

        List<String> queryIdList = dataQueryDto.getClassifyIdList();
        List<String> classifyIdList = classifyService.getByIdList(queryIdList);
        if (CollectionUtil.isEmpty(classifyIdList)) {
            classifyIdList = queryIdList;
        }
        //根据分类id查询关联的点位信息
        QueryWrapper<ClassifyPointRel> queryPoint = new QueryWrapper<>();
        queryPoint.lambda().in(ClassifyPointRel::getClassifyId, classifyIdList).select(ClassifyPointRel::getPointCode, ClassifyPointRel::getClassifyId, ClassifyPointRel::getDataObtainType);
        List<ClassifyPointRel> pointRelList = classifyPointRelMapper.selectList(queryPoint);
        if (CollectionUtil.isEmpty(pointRelList)) {
            return reportVo;
        }
        //循环点位信息，判断是否有点位不符合查询条件
        Map<Integer, List<ClassifyPointRel>> relMap = pointRelList.stream().collect(Collectors.groupingBy(ClassifyPointRel::getDataObtainType));
        for (Integer type : relMap.keySet()) {
            List<ClassifyPointRel> relPointList = relMap.get(type);
            if (!checkIsNeedReturnEmpty(queryType, type)) {

                for (ClassifyPointRel classifyPointRel : relPointList) {
                    reportDataVoList.add(buildEmptyReportDataVo(dateTimeList, classifyPointRel, "本周期数据"));
                    reportDataVoList.add(buildEmptyYoYReportDataVo(dateTimeList, classifyPointRel, "同比变化"));
                }
                continue;
            }
            //查询数据
            List<String> pointCodeList = relPointList.stream().map(ClassifyPointRel::getPointCode).toList();
            List<PointData> thisPointDataList = getPointDataList(dateDto.getStartDay(), dateDto.getEndDay(), type, pointCodeList);
            List<PointData> lastPointDataList = getPointDataList(dateDto.getLastStartDay(), dateDto.getLastEndDay(), type, pointCodeList);
//            if (CollectionUtil.isEmpty(thisPointDataList)) {
//                for (ClassifyPointRel classifyPointRel : relPointList) {
//                    reportDataVoList.add(buildEmptyReportDataVo(dateTimeList, classifyPointRel,"本周期数据"));
//                    reportDataVoList.add(buildEmptyYoYReportDataVo(dateTimeList, classifyPointRel,"同比变化"));
//                }
//                continue;
//            }
            //将数据处理为map结构map<点位编码，Map<X轴时间格式，数据值>>
            //按照查询类型和数据类型对数据时间进行处理，并分组，将数据处理为x轴需要的格式进行匹配
            Map<String, Map<String, BigDecimal>> thisMap = buildPointDataByDataType(thisPointDataList, queryType);
            Map<String, Map<String, BigDecimal>> lastMap = buildPointDataByDataType(lastPointDataList, queryType);
            Map<String, String> dateTimeMap = DateUtils.getThisAndLastDateMap(queryType, dateDto);
            for (ClassifyPointRel classifyPointRel : relPointList) {
                String pointCode = classifyPointRel.getPointCode();
                Map<String, BigDecimal> thisPointDataMap = thisMap.get(pointCode);
                Map<String, BigDecimal> lastPointDataMap = lastMap.get(pointCode);
                Map<String, Object> dataMap = new HashMap<>();
                Map<String, Object> yoyDataMap = new HashMap<>();
                BigDecimal total = BigDecimal.ZERO;
                for (String dateTimeStr : dateTimeList) {
                    BigDecimal data = BigDecimal.ZERO;
                    if (CollectionUtil.isNotEmpty(thisPointDataMap)) {
                        if (thisPointDataMap.containsKey(dateTimeStr)) {
                            data = thisPointDataMap.get(dateTimeStr);
                            dataMap.put(dateTimeStr, data.setScale(2, RoundingMode.HALF_UP));
                        } else {
                            dataMap.put(dateTimeStr, BigDecimal.ZERO);
                        }
                    } else {
                        dataMap.put(dateTimeStr, BigDecimal.ZERO);
                    }

                    total = total.add(data);
                    //计算同比
                    if (CollectionUtil.isNotEmpty(lastPointDataMap)) {
                        String lastDateTime = dateTimeMap.get(dateTimeStr);
                        if (StrUtil.isEmpty(lastDateTime)) {
                            yoyDataMap.put(dateTimeStr, "0%");
                        } else {
                            if (lastPointDataMap.containsKey(lastDateTime)) {
                                BigDecimal lastData = lastPointDataMap.get(lastDateTime);
                                BigDecimal yoyDataValue = getYoyValue(data, lastData);
                                yoyDataMap.put(dateTimeStr, yoyDataValue + "%");
                            } else {
                                yoyDataMap.put(dateTimeStr, "0%");
                            }
                        }

                    } else {
                        yoyDataMap.put(dateTimeStr, "0%");
                    }
                }
                //计算合计
                ReportDataVo reportDataVo = buildEmptyReportDataVo(dateTimeList, classifyPointRel, "本周期数据");
                reportDataVo.setDataMap(dataMap);
                reportDataVo.setTotalCount(total.setScale(2, RoundingMode.HALF_UP));
                reportDataVoList.add(reportDataVo);
                ReportDataVo yoyDataVo = buildEmptyReportDataVo(dateTimeList, classifyPointRel, "同比变化");
                yoyDataVo.setDataMap(yoyDataMap);
                reportDataVoList.add(yoyDataVo);
            }
            reportVo.setDataVoList(reportDataVoList);
        }
        return reportVo;
    }

    @Override
    public ReportVo deviceCompareLineReport(DataQueryDto dataQueryDto) {
        //根据查询条件计算起止时间
        String queryType = dataQueryDto.getQueryType();
        DateDto dateDto = DateUtils.dateQueryConvert(queryType, dataQueryDto.getStartDay(), dataQueryDto.getEndDay(), true);
        //构建x轴
        List<LocalDateTime> list = DateUtils.dateToList(queryType, dateDto.getStartDay(), dateDto.getEndDay());
        ReportVo reportVo = new ReportVo();
        List<String> dateTimeList = DateUtils.xAxisConvert(queryType, list);
        reportVo.setDateTimeList(dateTimeList);
        List<ReportDataVo> reportDataVoList = new ArrayList<>();

        // 获取分类设备
        List<DataQueryDto.ClassDevice> deviceList = dataQueryDto.getDeviceList();

        deviceList.forEach(classDevice -> {
            List<ClassifyDeviceProperty> property = classifyDevicePropertyService.getByClassifyIdAndDeviceId(classDevice.getClassifyId(), classDevice.getDeviceId());
            DeviceEntity device = deviceService.getById(classDevice.getDeviceId());
            if (CollectionUtil.isEmpty(property)) {
                reportDataVoList.add(buildEmptyReportDataVo(dateTimeList, device, "本周期数据"));
                reportDataVoList.add(buildEmptyYoYReportDataVo(dateTimeList, device, "同比变化"));
                return;
            }
            ClassifyDeviceProperty classifyDeviceProperty = property.get(0);
            Classify classify = classifyService.getById(classDevice.getClassifyId());
//            List<DeviceMeasureDateDTO> thisDeviceMeasureDateDTOS = getDeviceMeasureDateDtos(queryType, dateDto.getStartDay(), dateDto.getEndDay(), classify, Set.of(classDevice.getDeviceId()), classifyDeviceProperty.getDataTypeId());
//            List<DeviceMeasureDateDTO> lastDeviceMeasureDateDTOS = getDeviceMeasureDateDtos(queryType, dateDto.getLastStartDay(), dateDto.getLastEndDay(), classify, Set.of(classDevice.getDeviceId()), classifyDeviceProperty.getDataTypeId());
            List<DeviceMeasureDateDTO> thisDeviceMeasureDateDTOS = getDeviceMeasureDateTypeDtos(queryType, dateDto.getStartDay(), dateDto.getEndDay(), classify, Set.of(classDevice.getDeviceId()), classifyDeviceProperty.getDataTypeId(), classifyDeviceProperty.getCalculateType());
            List<DeviceMeasureDateDTO> lastDeviceMeasureDateDTOS = getDeviceMeasureDateTypeDtos(queryType, dateDto.getLastStartDay(), dateDto.getLastEndDay(), classify, Set.of(classDevice.getDeviceId()), classifyDeviceProperty.getDataTypeId(), classifyDeviceProperty.getCalculateType());

            if (CollectionUtil.isEmpty(thisDeviceMeasureDateDTOS) && CollectionUtil.isEmpty(lastDeviceMeasureDateDTOS)) {
                reportDataVoList.add(buildEmptyReportDataVo(dateTimeList, device, "本周期数据"));
                reportDataVoList.add(buildEmptyYoYReportDataVo(dateTimeList, device, "同比变化", "--"));
                return;
            } else if (CollectionUtil.isEmpty(thisDeviceMeasureDateDTOS) && CollectionUtil.isNotEmpty(lastDeviceMeasureDateDTOS)) {
                reportDataVoList.add(buildEmptyReportDataVo(dateTimeList, device, "本周期数据"));
                reportDataVoList.add(buildEmptyYoYReportDataVo(dateTimeList, device, "同比变化", "100%"));
                return;
            }

//            multipleProcess(thisDeviceMeasureDateDtos, classifyDeviceProperty.getMultiple());
//            multipleProcess(lastDeviceMeasureDateDtos, classifyDeviceProperty.getMultiple());

            //将数据处理为map结构map<点位编码，Map<X轴时间格式，数据值>>
            //按照查询类型和数据类型对数据时间进行处理，并分组，将数据处理为x轴需要的格式进行匹配
            Map<String, Map<String, BigDecimal>> thisMap = buildDeviceDataByDataType(thisDeviceMeasureDateDTOS, device.getCode());
            Map<String, Map<String, BigDecimal>> lastMap = buildDeviceDataByDataType(lastDeviceMeasureDateDTOS, device.getCode());
            Map<String, String> dateTimeMap = DateUtils.getThisAndLastDateMap(queryType, dateDto);
            String pointCode = device.getCode();
            Map<String, BigDecimal> thisPointDataMap = thisMap.get(pointCode);
            Map<String, BigDecimal> lastPointDataMap = lastMap.get(pointCode);
            Map<String, Object> dataMap = new HashMap<>();
            Map<String, Object> yoyDataMap = new HashMap<>();
            BigDecimal total = BigDecimal.ZERO;
            BigDecimal lastTotal = BigDecimal.ZERO;
            for (String dateTimeStr : dateTimeList) {
                BigDecimal data = BigDecimal.ZERO;
                if (CollectionUtil.isNotEmpty(thisPointDataMap)) {
                    if (thisPointDataMap.containsKey(dateTimeStr)) {
                        data = thisPointDataMap.get(dateTimeStr);
                        dataMap.put(dateTimeStr, data.setScale(2, RoundingMode.HALF_UP));
                    } else {
                        dataMap.put(dateTimeStr, BigDecimal.ZERO);
                    }
                } else {
                    dataMap.put(dateTimeStr, BigDecimal.ZERO);
                }

                total = total.add(data);
                //计算同比
                if (CollectionUtil.isNotEmpty(lastPointDataMap)) {
                    String lastDateTime = dateTimeMap.get(dateTimeStr);
                    if (StrUtil.isEmpty(lastDateTime)) {
                        yoyDataMap.put(dateTimeStr, "--");
                    } else {
                        if (lastPointDataMap.containsKey(lastDateTime)) {
                            BigDecimal lastData = lastPointDataMap.get(lastDateTime);
                            lastTotal = lastTotal.add(lastData);
                            BigDecimal yoyDataValue = getYoyValue(data, lastData);
                            yoyDataMap.put(dateTimeStr, yoyDataValue + "%");
                        } else {
                            yoyDataMap.put(dateTimeStr, "--");
                        }
                    }

                } else {
                    yoyDataMap.put(dateTimeStr, "--");
                }
            }
            //计算合计
            ReportDataVo reportDataVo = buildEmptyReportDataVo(dateTimeList, device, "本周期数据");
            reportDataVo.setDataMap(dataMap);
            reportDataVo.setTotalCount(total.setScale(2, RoundingMode.HALF_UP));
            reportDataVoList.add(reportDataVo);
            ReportDataVo yoyDataVo = buildEmptyReportDataVo(dateTimeList, device, "同比变化");
            yoyDataVo.setDataMap(yoyDataMap);
            BigDecimal yoyDataValue1 = getYoyValue(total, lastTotal);
            yoyDataVo.setTotalCount(yoyDataValue1 + "%");
            reportDataVoList.add(yoyDataVo);

        });

        reportVo.setDataVoList(reportDataVoList);

        return reportVo;
    }

    @Override
    public EnergyReportVo energyReport(DataQueryDto dataQueryDto) {
        //根据查询条件计算起止时间
        String queryType = dataQueryDto.getQueryType();
        DateDto dateDto = DateUtils.dateQueryConvert(queryType, dataQueryDto.getStartDay(), dataQueryDto.getEndDay(), true);
        Classify parentClassify = classifyService.getById(dataQueryDto.getClassifyId());
        EnergyReportVo reportVo = new EnergyReportVo();
        List<LocalDateTime> list = DateUtils.dateToList(queryType, dateDto.getStartDay(), dateDto.getEndDay());
        List<String> dateTimeList = DateUtils.xAxisConvert(queryType, list);
        reportVo.setDateTimeList(dateTimeList);
//        //判断是否符合查询要求
//        if (checkIsNeedReturnEmpty(queryType, parentClassify.getDataObtainType())) {
//            return reportVo;
//        }
        List<Classify> classifyList = new ArrayList<>();
        if (parentClassify.getCountType() == ClassifyCountType.POINT_COUNT) {
            classifyList.add(parentClassify);
        } else {
            classifyList = classifyService.getChildrenClassify(dataQueryDto.getClassifyId());
        }
        //map<分类id，map<时间，数据>>
        Map<String, Map<String, DataVo>> dataMap = new HashMap<>();
        Map<String, String> dateTimeMap = DateUtils.getThisAndLastDateMap(queryType, dateDto);
        for (Classify classify : classifyList) {
            List<ClassifyDeviceProperty> devicePropertyList = getClassifyDeviceProperties(classify.getClassifyId());

            if (CollectionUtil.isEmpty(devicePropertyList)) {
                continue;
            }

            Set<String> deviceIdSet = devicePropertyList.stream().map(ClassifyDeviceProperty::getDeviceId).collect(Collectors.toSet());
            ClassifyDeviceProperty classifyDeviceProperty = devicePropertyList.get(0);
            String dataTypeId = classifyDeviceProperty.getDataTypeId();
            Integer calculateType = classifyDeviceProperty.getCalculateType();

            List<DeviceMeasureDateDTO> thisPointDataList = getDeviceMeasureDateTypeDtos(queryType, dateDto.getStartDay(), dateDto.getEndDay(),
                    classify, deviceIdSet, dataTypeId, calculateType);
            List<DeviceMeasureDateDTO> lastPointDataList = getDeviceMeasureDateTypeDtos(queryType, dateDto.getLastStartDay(), dateDto.getLastEndDay(),
                    classify, deviceIdSet, dataTypeId, calculateType);


            //根据分类id查询所有的下级分类id
            Map<String, DataVo> classifyDataMap = new HashMap<>();
//            List<String> classifyIdList = classifyService.getClassifyId(classify.getClassifyId());
//            //根据分类id查询关联的点位信息
//            QueryWrapper<ClassifyPointRel> queryPoint = new QueryWrapper<>();
//            queryPoint.lambda().in(ClassifyPointRel::getClassifyId, classifyIdList).select(ClassifyPointRel::getPointCode, ClassifyPointRel::getClassifyId, ClassifyPointRel::getDataObtainType);
//            List<ClassifyPointRel> pointRelList = classifyPointRelMapper.selectList(queryPoint);
//            List<String> pointCodeList = pointRelList.stream().map(ClassifyPointRel::getPointCode).toList();
//            //查询点位数据
//            List<PointData> thisPointDataList = new ArrayList<>();
//            List<PointData> lastPointDataList = new ArrayList<>();
//            ;
//            if (!pointCodeList.isEmpty()) {
//                thisPointDataList = getPointDataList(dateDto.getStartDay(), dateDto.getEndDay(), classify.getDataObtainType(), pointCodeList);
//                lastPointDataList = getPointDataList(dateDto.getLastStartDay(), dateDto.getLastEndDay(), classify.getDataObtainType(), pointCodeList);
//            }


            Map<String, List<DeviceMeasureDateDTO>> thisMap = buildDataByDataType(thisPointDataList, queryType);
            Map<String, List<DeviceMeasureDateDTO>> lastMap = buildDataByDataType(lastPointDataList, queryType);


            buildData(thisMap, lastMap, dateTimeList, dateTimeMap, classify.getClassifyId(), classifyDataMap);
            dataMap.put(classify.getClassifyId(), classifyDataMap);
        }


        //组装数据
//        reportVo.setThisData(buildEnergyData(dataMap,dateTimeList,parentClassify));
        reportVo.setCompareDataList(buildCompareData(dataMap, dateTimeList, parentClassify));
        reportVo.setPercentDataList(buildPercentData(dataMap, dateTimeList, classifyList));
        return reportVo;
    }

    @Override
    public EnergyReportVo pointReport(DataQueryDto dataQueryDto) {
        //根据查询条件计算起止时间
        String queryType = dataQueryDto.getQueryType();
        DateDto dateDto = DateUtils.dateQueryConvert(queryType, dataQueryDto.getStartDay(), dataQueryDto.getEndDay(), true);
        //构建x轴
        List<LocalDateTime> list = DateUtils.dateToList(queryType, dateDto.getStartDay(), dateDto.getEndDay());
        EnergyReportVo reportVo = new EnergyReportVo();
        List<String> dateTimeList = DateUtils.xAxisConvert(queryType, list);
        reportVo.setDateTimeList(dateTimeList);
        List<String> queryIdList = dataQueryDto.getClassifyIdList();
        List<String> classifyIdList = classifyService.getByIdList(queryIdList);
        if (CollectionUtil.isEmpty(classifyIdList)) {
            classifyIdList = queryIdList;
        }
        //根据分类id查询关联的点位信息
        QueryWrapper<ClassifyPointRel> queryPoint = new QueryWrapper<>();
        queryPoint.lambda().in(ClassifyPointRel::getClassifyId, classifyIdList).select(ClassifyPointRel::getPointCode, ClassifyPointRel::getClassifyId, ClassifyPointRel::getDataObtainType);
        List<ClassifyPointRel> pointRelList = classifyPointRelMapper.selectList(queryPoint);
        if (CollectionUtil.isEmpty(pointRelList)) {
            return reportVo;
        }
        //循环点位信息，判断是否有点位不符合查询条件
        Map<Integer, List<ClassifyPointRel>> relMap = pointRelList.stream().collect(Collectors.groupingBy(ClassifyPointRel::getDataObtainType));
        //map<pointcode,Map<datetime,datavo>>
        Map<String, Map<String, DataVo>> map = new HashMap<>();
        Map<String, String> dateTimeMap = DateUtils.getThisAndLastDateMap(queryType, dateDto);
        for (Integer type : relMap.keySet()) {
            List<ClassifyPointRel> relPointList = relMap.get(type);
            if (!checkIsNeedReturnEmpty(queryType, type)) {
                for (ClassifyPointRel classifyPointRel : relPointList) {
                    map.put(classifyPointRel.getPointCode(), buildEmptyDataVo(dateTimeList, classifyPointRel.getPointCode()));
                }
                continue;
            }
            //查询数据
            List<String> pointCodeList = relPointList.stream().map(ClassifyPointRel::getPointCode).toList();
            List<PointData> thisPointDataList = getPointDataList(dateDto.getStartDay(), dateDto.getEndDay(), type, pointCodeList);
            List<PointData> lastPointDataList = getPointDataList(dateDto.getLastStartDay(), dateDto.getLastEndDay(), type, pointCodeList);
            Map<String, Map<String, BigDecimal>> thisMap = buildPointDataByDataType(thisPointDataList, queryType);
            Map<String, Map<String, BigDecimal>> lastMap = buildPointDataByDataType(lastPointDataList, queryType);
            buildPointData(thisMap, lastMap, pointCodeList, dateTimeList, dateTimeMap, map);
        }
        reportVo.setThisDataList(buildThisDataList(map, dateTimeList));
        reportVo.setCompareDataList(buildPointCompareDataList(map, dateTimeList));
        return reportVo;
    }

    private List<ReportDataVo> buildPointCompareDataList(Map<String, Map<String, DataVo>> map, List<String> dateTimeList) {
        List<ReportDataVo> list = new ArrayList<>();
        for (Map.Entry<String, Map<String, DataVo>> entry : map.entrySet()) {
            String pointCode = entry.getKey();
            ReportDataVo thisDataVo = new ReportDataVo();
            thisDataVo.setClassifyName(pointCode);
            thisDataVo.setItemName("本周期数据");
            Map<String, Object> returnDataMap = new HashMap<>();
            ReportDataVo percentDataVo = new ReportDataVo();
            percentDataVo.setClassifyName(pointCode);
            percentDataVo.setItemName("同比变化");
            Map<String, Object> percentDataMap = new HashMap<>();


            Map<String, DataVo> timeDataMap = entry.getValue();
            BigDecimal total = BigDecimal.ZERO;
            for (String dateTime : dateTimeList) {
                DataVo dataVo = timeDataMap.get(dateTime);
                BigDecimal thisData = dataVo.getThisValue();
                total = total.add(thisData);
                returnDataMap.put(dateTime, thisData.setScale(2, RoundingMode.HALF_UP));
                //计算同比
                BigDecimal lastData = dataVo.getLastValue();
                String percent = getPercent(thisData, lastData);
                percentDataMap.put(dateTime, percent);
            }
            thisDataVo.setDataMap(returnDataMap);
            thisDataVo.setTotalCount(total.setScale(2, RoundingMode.HALF_UP));
            list.add(thisDataVo);
            percentDataVo.setDataMap(percentDataMap);
            list.add(percentDataVo);
        }
        return list;
    }

    private List<ReportDataVo> buildThisDataList(Map<String, Map<String, DataVo>> map, List<String> dateTimeList) {
        List<ReportDataVo> list = new ArrayList<>();
        Map<String, Object> dateTotalCountMap = new HashMap<>();
        BigDecimal allTotal = BigDecimal.ZERO;
        for (Map.Entry<String, Map<String, DataVo>> entry : map.entrySet()) {
            ReportDataVo reportDataVo = new ReportDataVo();
            String pointCode = entry.getKey();
            reportDataVo.setClassifyName(pointCode);
            Map<String, Object> returnDataMap = new HashMap<>();
            Map<String, DataVo> timeDataMap = entry.getValue();
            BigDecimal total = BigDecimal.ZERO;
            for (String dateTime : dateTimeList) {
                DataVo dataVo = timeDataMap.get(dateTime);
                BigDecimal thisData = dataVo.getThisValue();
                total = total.add(thisData);
                returnDataMap.put(dateTime, thisData.setScale(2, RoundingMode.HALF_UP));
                if (dateTotalCountMap.containsKey(dateTime)) {
                    BigDecimal count = (BigDecimal) dateTotalCountMap.get(dateTime);
                    count = count.add(thisData);
                    dateTotalCountMap.put(dateTime, count);
                } else {
                    dateTotalCountMap.put(dateTime, thisData);
                }
            }
            allTotal = allTotal.add(total);
            reportDataVo.setDataMap(returnDataMap);
            reportDataVo.setTotalCount(total.setScale(2, RoundingMode.HALF_UP));
            list.add(reportDataVo);
        }
        //合计
        ReportDataVo reportDataVo = new ReportDataVo();
        reportDataVo.setClassifyName("合计");
        //进行四舍五入
        for (String dateTime : dateTotalCountMap.keySet()) {
            BigDecimal data = (BigDecimal) dateTotalCountMap.get(dateTime);
            dateTotalCountMap.put(dateTime, data.setScale(2, RoundingMode.HALF_UP));
        }
        reportDataVo.setDataMap(dateTotalCountMap);
        reportDataVo.setTotalCount(allTotal.setScale(2, RoundingMode.HALF_UP));
        list.add(reportDataVo);
        return list;
    }


    private void buildPointData(Map<String, Map<String, BigDecimal>> thisMap, Map<String, Map<String, BigDecimal>> lastMap,
                                List<String> pointCodeList, List<String> dateTimeList, Map<String, String> dateTimeMap,
                                Map<String, Map<String, DataVo>> map) {
        for (String pointCode : pointCodeList) {
            Map<String, DataVo> timeMap = new HashMap<>();
            for (String dateTime : dateTimeList) {
                DataVo dataVo = new DataVo();
                dataVo.setPointCode(pointCode);
                dataVo.setDateTime(dateTime);
                timeMap.put(dateTime, dataVo);
            }
            map.put(pointCode, timeMap);
        }
        //循环数据
        for (Map.Entry<String, Map<String, BigDecimal>> entry : thisMap.entrySet()) {
            String pointCode = entry.getKey();
            Map<String, DataVo> returnTimeMap = map.get(pointCode);
            Map<String, BigDecimal> timeDataMap = entry.getValue();
            for (Map.Entry<String, BigDecimal> timeDataEntry : timeDataMap.entrySet()) {
                String dateTime = timeDataEntry.getKey();
                BigDecimal dataValue = timeDataMap.get(dateTime);
                DataVo dataVo = returnTimeMap.get(dateTime);
                dataVo.setThisValue(dataValue);
            }
        }
        for (Map.Entry<String, Map<String, BigDecimal>> entry : lastMap.entrySet()) {
            String pointCode = entry.getKey();
            Map<String, DataVo> returnTimeMap = map.get(pointCode);
            Map<String, BigDecimal> valueMap = entry.getValue();
            for (String dateTime : returnTimeMap.keySet()) {
                String lastTime = dateTimeMap.get(dateTime);
                DataVo dataVo = returnTimeMap.get(dateTime);
                if (StrUtil.isEmpty(lastTime)) {
                    dataVo.setLastValue(BigDecimal.ZERO);
                } else {
                    BigDecimal lastValue = valueMap.get(lastTime);
                    dataVo.setLastValue(lastValue);
                }
            }
        }

    }


    private Map<String, DataVo> buildEmptyDataVo(List<String> dateTimeList, String pointCode) {
        Map<String, DataVo> map = new HashMap<>();
        for (String dateTime : dateTimeList) {
            DataVo dataVo = new DataVo();
            dataVo.setPointCode(pointCode);
            dataVo.setDateTime(dateTime);
            map.put(dateTime, dataVo);
        }
        return map;
    }

    private List<ReportDataVo> buildPercentData(Map<String, Map<String, DataVo>> dataMap, List<String> dateTimeList, List<Classify> classifyList) {
        //计算每个日期的总值
        Map<String, BigDecimal> map = new HashMap<>();
        for (Map<String, DataVo> dataVoMap : dataMap.values()) {
            for (String dateTime : dataVoMap.keySet()) {
                DataVo dataVo = dataVoMap.get(dateTime);
                if (map.containsKey(dateTime)) {
                    BigDecimal data = map.get(dateTime);
                    if (dataVo.getThisValue() != null) {
                        data = data.add(dataVo.getThisValue());
                    }
                    map.put(dateTime, data);
                } else {
                    map.put(dateTime, dataVo.getThisValue());
                }
            }
        }
        List<ReportDataVo> reportDataVoList = new ArrayList<>();
        for (Classify classify : classifyList) {
            ReportDataVo reportDataVo = new ReportDataVo();
            reportDataVo.setClassifyName(classify.getClassifyName());
            Map<String, Object> returnDataMap = new HashMap<>();
            Map<String, DataVo> classifyDataMap = dataMap.get(classify.getClassifyId());
            for (String dateTime : dateTimeList) {
                if (classifyDataMap == null) {
                    returnDataMap.put(dateTime, "0%");
                    continue;
                }
                DataVo dataVo = classifyDataMap.get(dateTime);
                BigDecimal total = map.get(dateTime);
                if (total == null) {
                    returnDataMap.put(dateTime, "--");
                } else if (BigDecimal.ZERO.compareTo(total) == 0) {
                    returnDataMap.put(dateTime, "0%");
                } else {
                    BigDecimal bigDecimal = dataVo.getThisValue().setScale(2, RoundingMode.HALF_UP).divide(total, 2, RoundingMode.HALF_UP).multiply(new BigDecimal(100)).setScale(2, RoundingMode.HALF_UP);
                    String percent = BigDecimal.ZERO.compareTo(bigDecimal) == 0 ? "0%" : bigDecimal + "%";
                    returnDataMap.put(dateTime, percent);
                }

            }
            reportDataVo.setDataMap(returnDataMap);
            reportDataVoList.add(reportDataVo);
        }
        return reportDataVoList;
    }

    private List<ReportDataVo> buildCompareData(Map<String, Map<String, DataVo>> dataMap, List<String> dateTimeList, Classify parentClassify) {
        ReportDataVo thisDataVo = new ReportDataVo();
        thisDataVo.setClassifyName(parentClassify.getClassifyName());
        thisDataVo.setItemName("本周期");
        ReportDataVo lastDataVo = new ReportDataVo();
        lastDataVo.setClassifyName(parentClassify.getClassifyName());
        lastDataVo.setItemName("上个周期");
        ReportDataVo percentDataVo = new ReportDataVo();
        percentDataVo.setClassifyName(parentClassify.getClassifyName());
        percentDataVo.setItemName("同比变化");

        Map<String, Object> thisMap = new HashMap<>();
        BigDecimal thisTotal = BigDecimal.ZERO;
        Map<String, Object> lastMap = new HashMap<>();
        BigDecimal lastTotal = BigDecimal.ZERO;
        Map<String, Object> percentMap = new HashMap<>();
        for (String dateTime : dateTimeList) {
            BigDecimal thisData = BigDecimal.ZERO;
            BigDecimal lastData = BigDecimal.ZERO;
            for (Map<String, DataVo> dataVoMap : dataMap.values()) {
                DataVo dataVo = dataVoMap.get(dateTime);
                if (dataVo.getThisValue() != null) {
                    thisData = thisData.add(dataVo.getThisValue());
                }
                if (dataVo.getLastValue() != null) {
                    lastData = lastData.add(dataVo.getLastValue());
                }

            }
            thisMap.put(dateTime, thisData.setScale(2, RoundingMode.HALF_UP));
            thisTotal = thisTotal.add(thisData);
            lastMap.put(dateTime, lastData.setScale(2, RoundingMode.HALF_UP));
            lastTotal = lastTotal.add(lastData);
            String percent = getPercent(thisData, lastData);
            percentMap.put(dateTime, percent);
        }
        thisDataVo.setDataMap(thisMap);
        thisDataVo.setTotalCount(thisTotal.setScale(2, RoundingMode.HALF_UP));
        lastDataVo.setDataMap(lastMap);
        lastDataVo.setTotalCount(lastTotal.setScale(2, RoundingMode.HALF_UP));
        String totalPercent = getPercent(thisTotal, lastTotal);
        percentDataVo.setDataMap(percentMap);
        percentDataVo.setTotalCount(totalPercent);
        return List.of(thisDataVo, lastDataVo, percentDataVo);
    }

    private String getPercent(BigDecimal thisValue, BigDecimal lastValue) {
        if (BigDecimal.ZERO.compareTo(lastValue) == 0 && BigDecimal.ZERO.compareTo(thisValue) == 0) {
            return "0%";
        }
        if (BigDecimal.ZERO.compareTo(lastValue) == 0) {
            return "100%";
        }
        return thisValue.subtract(lastValue).divide(lastValue, 2, RoundingMode.HALF_UP).multiply(new BigDecimal(100)).setScale(2, RoundingMode.HALF_UP) + "%";
    }

    private ReportDataVo buildEnergyData(Map<String, Map<String, DataVo>> dataMap, List<String> dateTimeList, Classify classify) {
        ReportDataVo reportDataVo = new ReportDataVo();
        reportDataVo.setClassifyName(classify.getClassifyName());
        Map<String, Object> map = new HashMap<>();
        BigDecimal total = BigDecimal.ZERO;
        for (String dateTime : dateTimeList) {
            BigDecimal data = BigDecimal.ZERO;
            for (Map<String, DataVo> dataVoMap : dataMap.values()) {
                DataVo dataVo = dataVoMap.get(dateTime);
                data = data.add(dataVo.getThisValue());
            }
            map.put(dateTime, data.setScale(2, RoundingMode.HALF_UP));
            total = total.add(data);
        }
        reportDataVo.setDataMap(map);
        reportDataVo.setTotalCountYs(total);
        reportDataVo.setTotalCount(total.setScale(2, RoundingMode.HALF_UP));
        return reportDataVo;
    }

    private void buildData(Map<String, List<DeviceMeasureDateDTO>> thisMap, Map<String, List<DeviceMeasureDateDTO>> lastMap,
                           List<String> dateTimeList,
                           Map<String, String> dateTimeMap, String classifyId, Map<String, DataVo> classifyDataMap) {
        for (String dateTime : dateTimeList) {
            DataVo dataVo = new DataVo();
            dataVo.setDateTime(dateTime);
            dataVo.setClassifyId(classifyId);
            BigDecimal thisData = BigDecimal.ZERO;
            BigDecimal lastData = BigDecimal.ZERO;
            if (thisMap.containsKey(dateTime)) {
                List<DeviceMeasureDateDTO> pointData = thisMap.get(dateTime);
                thisData = pointData.stream().map(DeviceMeasureDateDTO::getStatistic).reduce(BigDecimal.ZERO, BigDecimal::add);
            } else {
                thisData = null;
            }
            dataVo.setThisValue(thisData);
            String lastTime = dateTimeMap.get(dateTime);
            if (StrUtil.isNotEmpty(lastTime) && lastMap.containsKey(lastTime)) {
                List<DeviceMeasureDateDTO> pointData = lastMap.get(lastTime);
                lastData = pointData.stream().map(DeviceMeasureDateDTO::getStatistic).reduce(BigDecimal.ZERO, BigDecimal::add);
            } else {
                lastData = null;
            }
            dataVo.setLastValue(lastData);
            classifyDataMap.put(dateTime, dataVo);
        }
    }

    private void buildData(Map<String, List<PointData>> thisMap, Map<String, List<PointData>> lastMap,
                           List<String> dateTimeList, Map<String, DataVo> classifyDataMap,
                           Map<String, String> dateTimeMap, String classifyId) {
        for (String dateTime : dateTimeList) {
            DataVo dataVo = new DataVo();
            dataVo.setDateTime(dateTime);
            dataVo.setClassifyId(classifyId);
            BigDecimal thisData = BigDecimal.ZERO;
            BigDecimal lastData = BigDecimal.ZERO;
            if (thisMap.containsKey(dateTime)) {
                List<PointData> pointData = thisMap.get(dateTime);
                thisData = pointData.stream().map(PointData::getDataValue).reduce(BigDecimal.ZERO, BigDecimal::add);
            }
            dataVo.setThisValue(thisData);
            String lastTime = dateTimeMap.get(dateTime);
            if (StrUtil.isNotEmpty(lastTime) && lastMap.containsKey(lastTime)) {
                List<PointData> pointData = lastMap.get(lastTime);
                lastData = pointData.stream().map(PointData::getDataValue).reduce(BigDecimal.ZERO, BigDecimal::add);
            }
            dataVo.setLastValue(lastData);
            classifyDataMap.put(dateTime, dataVo);
        }
    }

    private BigDecimal getYoyValue(BigDecimal data, BigDecimal lastData) {
        if (BigDecimal.ZERO.compareTo(lastData) == 0) {
            return BigDecimal.ZERO;
        }
        return data.subtract(lastData).divide(lastData, 2, RoundingMode.HALF_UP)
                .multiply(new BigDecimal(100)).setScale(2, RoundingMode.HALF_UP);
    }

    private ReportDataVo buildEmptyYoYReportDataVo(List<String> dateTimeList, Classify classify, String itemName) {
        ReportDataVo reportDataVo = new ReportDataVo();
        reportDataVo.setClassifyName(classify.getClassifyName());
        reportDataVo.setItemName(itemName);
        Map<String, Object> map = new HashMap<>();
        for (String dateTime : dateTimeList) {
            map.put(dateTime, BigDecimal.ZERO + "%");
        }
        reportDataVo.setDataMap(map);
        return reportDataVo;
    }

    private ReportDataVo buildEmptyYoYReportDataVo(List<String> dateTimeList, ClassifyPointRel rel, String itemName) {
        ReportDataVo reportDataVo = new ReportDataVo();
        reportDataVo.setClassifyName(rel.getPointCode());
        reportDataVo.setItemName(itemName);
        Map<String, Object> map = new HashMap<>();
        for (String dateTime : dateTimeList) {
            map.put(dateTime, BigDecimal.ZERO + "%");
        }
        reportDataVo.setDataMap(map);
        return reportDataVo;
    }

    private ReportDataVo buildEmptyYoYReportDataVo(List<String> dateTimeList, DeviceEntity device, String itemName) {
        return buildEmptyYoYReportDataVo(dateTimeList, device, itemName, BigDecimal.ZERO + "%");
    }

    private ReportDataVo buildEmptyYoYReportDataVo(List<String> dateTimeList, DeviceEntity device, String itemName, String
            val) {
        ReportDataVo reportDataVo = new ReportDataVo();
        reportDataVo.setClassifyName(device.getName());
        reportDataVo.setItemName(itemName);
        Map<String, Object> map = new HashMap<>();
        for (String dateTime : dateTimeList) {
            map.put(dateTime, val);
        }
        reportDataVo.setDataMap(map);
        return reportDataVo;
    }

    private BigDecimal setMapValue(Map<String, List<PointData>> thisMap, Map<String, Object> dataMap, String dateTimeStr) {
        if (thisMap.containsKey(dateTimeStr)) {
            List<PointData> pointDataListByDate = thisMap.get(dateTimeStr);
            BigDecimal data = pointDataListByDate.stream().map(PointData::getDataValue).reduce(BigDecimal.ZERO, BigDecimal::add);
            dataMap.put(dateTimeStr, data.setScale(2, RoundingMode.HALF_UP));
            return data;
        } else {
            dataMap.put(dateTimeStr, BigDecimal.ZERO);
            return BigDecimal.ZERO;
        }
    }

    private BigDecimal setMapValue(Map<String, List<DeviceMeasureDateDTO>> thisMap, Map<String, Object> dataMap,
                                   String dateTimeStr, Integer countType) {
        if (thisMap.containsKey(dateTimeStr)) {
            List<DeviceMeasureDateDTO> pointDataListByDate = thisMap.get(dateTimeStr);
            BigDecimal data;
            if (countType.equals(ClassifyCountType.CLASSIFY_COUNT)) {
                data = pointDataListByDate.stream().map(DeviceMeasureDateDTO::getStatistic)
                        .reduce(BigDecimal.ZERO, BigDecimal::add);
            } else {
                data = pointDataListByDate.stream().map(DeviceMeasureDateDTO::getStatistic)
                        .reduce(BigDecimal.ZERO, BigDecimal::add).divide(BigDecimal.valueOf(pointDataListByDate.size()));
            }
            dataMap.put(dateTimeStr, data.setScale(2, RoundingMode.HALF_UP));
            return data;
        } else {
            dataMap.put(dateTimeStr, BigDecimal.ZERO);
            return BigDecimal.ZERO;
        }
    }

    private BigDecimal setMapValue(Map<String, List<PointData>> thisMap, String dateTimeStr) {
        if (thisMap.containsKey(dateTimeStr)) {
            List<PointData> pointDataListByDate = thisMap.get(dateTimeStr);
            BigDecimal data = pointDataListByDate.stream().map(PointData::getDataValue).reduce(BigDecimal.ZERO, BigDecimal::add);
            return data;
        }
        return BigDecimal.ZERO;
    }

    private ReportDataVo buildEmptyReportDataVo(List<String> dateTimeList, ClassifyPointRel classifyPointRel, String itemName) {
        ReportDataVo reportDataVo = new ReportDataVo();
        reportDataVo.setClassifyName(classifyPointRel.getPointCode());
        reportDataVo.setItemName(itemName);
        Map<String, Object> map = new HashMap<>();
        for (String dateTime : dateTimeList) {
            map.put(dateTime, BigDecimal.ZERO);
        }
        reportDataVo.setDataMap(map);
        return reportDataVo;
    }

    private ReportDataVo buildEmptyReportDataVo(List<String> dateTimeList, DeviceEntity device, String itemName) {
        ReportDataVo reportDataVo = new ReportDataVo();
        reportDataVo.setClassifyName(device.getName());
        reportDataVo.setItemName(itemName);
        Map<String, Object> map = new HashMap<>();
        for (String dateTime : dateTimeList) {
            map.put(dateTime, BigDecimal.ZERO);
        }
        reportDataVo.setDataMap(map);
        return reportDataVo;
    }

    private ReportDataVo buildEmptyReportDataVo(List<String> dateTimeList, Classify classify, String itemName) {
        ReportDataVo reportDataVo = new ReportDataVo();
        reportDataVo.setClassifyName(classify.getClassifyName());
        reportDataVo.setItemName(itemName);
        Map<String, Object> map = new HashMap<>();
        for (String dateTime : dateTimeList) {
            map.put(dateTime, BigDecimal.ZERO);
        }
        reportDataVo.setDataMap(map);
        return reportDataVo;
    }

    private static ChartYAxisVo buildEmptyChartYAxisVo(Integer size, ClassifyPointRel classifyPointRel, String type) {
        ChartYAxisVo chartYAxisVo = new ChartYAxisVo();
        chartYAxisVo.setName(classifyPointRel.getPointCode());

        chartYAxisVo.setStack(classifyPointRel.getPointId());
        List<BigDecimal> emptyDataList = new ArrayList<>();
        for (int i = 0; i < size; i++) {
            emptyDataList.add(BigDecimal.ZERO);
        }
        chartYAxisVo.setData(emptyDataList);
        return chartYAxisVo;
    }

    private static ChartYAxisVo buildEmptyChartYAxisVo(Integer size, DeviceEntity device, String type) {
        ChartYAxisVo chartYAxisVo = new ChartYAxisVo();
        chartYAxisVo.setName(device.getName());

        chartYAxisVo.setStack(device.getId());
        List<BigDecimal> emptyDataList = new ArrayList<>();
        for (int i = 0; i < size; i++) {
            emptyDataList.add(BigDecimal.ZERO);
        }
        chartYAxisVo.setData(emptyDataList);
        return chartYAxisVo;
    }

    private static ChartYAxisVo buildEmptyChartYAxisVo(Integer size, Classify classify, String type) {
        ChartYAxisVo chartYAxisVo = new ChartYAxisVo();
        chartYAxisVo.setName(classify.getClassifyName());

        chartYAxisVo.setStack(classify.getClassifyId());
        List<BigDecimal> emptyDataList = new ArrayList<>();
        for (int i = 0; i < size; i++) {
            emptyDataList.add(BigDecimal.ZERO);
        }
        chartYAxisVo.setData(emptyDataList);
        return chartYAxisVo;
    }

    private List<PieChartVo> buildPieChart(List<Classify> classifyList) {

        List<PieChartVo> list = new ArrayList<>();
        for (Classify childClassify : classifyList) {
            PieChartVo pieChartVo = new PieChartVo();
            pieChartVo.setClassifyId(childClassify.getClassifyId());
            pieChartVo.setName(childClassify.getClassifyName());
            pieChartVo.setValue(BigDecimal.ZERO);
            list.add(pieChartVo);
        }
        return list;
    }

    private static void setYValue(Map<String, List<PointData>> thisMap, List<BigDecimal> thisYValueList, String dateTimeStr) {
        if (thisMap.containsKey(dateTimeStr)) {
            List<PointData> pointDataListByDate = thisMap.get(dateTimeStr);
            BigDecimal data = pointDataListByDate.stream().map(PointData::getDataValue).reduce(BigDecimal.ZERO, BigDecimal::add);
            thisYValueList.add(data.setScale(2, RoundingMode.HALF_UP));
        } else {
            thisYValueList.add(BigDecimal.ZERO);
        }
    }

    private static void setYVal(Map<String, List<DeviceMeasureDateDTO>> thisMap, List<BigDecimal> thisYValueList, String dateTimeStr) {
        if (thisMap.containsKey(dateTimeStr)) {
            List<DeviceMeasureDateDTO> pointDataListByDate = thisMap.get(dateTimeStr);
            BigDecimal data = pointDataListByDate.stream().map(DeviceMeasureDateDTO::getStatistic).reduce(BigDecimal.ZERO, BigDecimal::add);
            thisYValueList.add(data.setScale(2, RoundingMode.HALF_UP));
        } else {
            thisYValueList.add(BigDecimal.ZERO);
        }
    }

    private static void setYVal(Map<String, List<DeviceMeasureDateDTO>> thisMap, List<BigDecimal> thisYValueList, String dateTimeStr, Integer type) {
        if (thisMap.containsKey(dateTimeStr)) {
            List<DeviceMeasureDateDTO> pointDataListByDate = thisMap.get(dateTimeStr);
            BigDecimal data = BigDecimal.ZERO;
            if (type == null || type.equals(EnergyDataTypeEnum.ENERGY.getCode())) {
                data = pointDataListByDate.stream().map(DeviceMeasureDateDTO::getStatistic).reduce(BigDecimal.ZERO, BigDecimal::add);
            } else if (type.equals(EnergyDataTypeEnum.CODE.getCode())) {
                data = pointDataListByDate.stream().map(v -> v.getCost() == null ? BigDecimal.ZERO : v.getCost()).reduce(BigDecimal.ZERO, BigDecimal::add);
            }
            thisYValueList.add(data.setScale(2, RoundingMode.HALF_UP));
        } else {
            thisYValueList.add(BigDecimal.ZERO);
        }
    }

    private ChartVo buildCompareEmpty(String queryType, List<LocalDateTime> list) {
        //根据查询类型格式化x轴信息
        List<String> xAxisList = DateUtils.xAxisConvert(queryType, list);
        ChartYAxisVo thisChartYAxisVo = new ChartYAxisVo();
        thisChartYAxisVo.setName("本周期");

        thisChartYAxisVo.setStack("this");
        ChartYAxisVo lastChartYAxisVo = new ChartYAxisVo();
        lastChartYAxisVo.setName("上周期");

        lastChartYAxisVo.setStack("last");

        List<BigDecimal> thisDataValueList = new ArrayList<>();
        List<BigDecimal> lastDataValueList = new ArrayList<>();
        for (String dateStr : xAxisList) {
            thisDataValueList.add(BigDecimal.ZERO);
            lastDataValueList.add(BigDecimal.ZERO);
        }
        thisChartYAxisVo.setData(thisDataValueList);
        lastChartYAxisVo.setData(lastDataValueList);
        ChartVo chartVo = new ChartVo();
        chartVo.setXAxisList(xAxisList);
        chartVo.setYAxisList(List.of(lastChartYAxisVo, thisChartYAxisVo));
        return chartVo;
    }

    private List<PointData> getPointDataList(String startDateStr, String endDateStr, Integer dataObtainType, List<String> pointCodeList) {
        String startTimeCondition = QueryUtils.getStartTime(dataObtainType, startDateStr);
        String endTimeCondition = QueryUtils.getEndTime(dataObtainType, endDateStr);
//        String startTimeCondition = startDateStr;
//        String endTimeCondition = endDateStr;

        //查询对应的点位数据
        QueryWrapper<PointData> query = new QueryWrapper<>();
        query.lambda().in(PointData::getPointCode, pointCodeList)
                .eq(PointData::getDataObtainType, dataObtainType)
                .between(PointData::getDataTime, startTimeCondition, endTimeCondition);
        return pointDataMapper.selectList(query);
    }

    private Map<String, List<DeviceMeasureDateDTO>> buildDataByDataType(List<DeviceMeasureDateDTO> pointDataList, String queryType) {
        //如果查询的不是日数据，且是自动的点位，需要把数据时间转换为天进行分组
        Map<String, List<DeviceMeasureDateDTO>> map = new HashMap<>();
        if (CollectionUtil.isEmpty(pointDataList)) {
            return map;
        }
        for (DeviceMeasureDateDTO pointData : pointDataList) {
            String dateStr = pointData.getDayStr();
            if (map.containsKey(dateStr)) {
                List<DeviceMeasureDateDTO> dataList = map.get(dateStr);
                dataList.add(pointData);
            } else {
                List<DeviceMeasureDateDTO> newList = new ArrayList<>();
                newList.add(pointData);
                map.put(dateStr, newList);
            }
        }
        return map;
    }


    private Map<String, List<DeviceMeasureDateDTO>> buildDataByDataType(List<DeviceMeasureDateDTO> pointDataList) {
        //如果查询的不是日数据，且是自动的点位，需要把数据时间转换为天进行分组
        Map<String, List<DeviceMeasureDateDTO>> map = new HashMap<>();
        if (CollectionUtil.isEmpty(pointDataList)) {
            return map;
        }
        for (DeviceMeasureDateDTO pointData : pointDataList) {
            String dateStr = pointData.getDayStr();
            if (map.containsKey(dateStr)) {
                List<DeviceMeasureDateDTO> dataList = map.get(dateStr);
                dataList.add(pointData);
            } else {
                List<DeviceMeasureDateDTO> newList = new ArrayList<>();
                newList.add(pointData);
                map.put(dateStr, newList);
            }
        }
        return map;
    }

    private ChartVo buildEmpty(String queryType, List<LocalDateTime> list, String classifyName) {
        //根据查询类型格式化x轴信息
        List<String> xAxisList = DateUtils.xAxisConvert(queryType, list);
        ChartYAxisVo chartYAxisVo = new ChartYAxisVo();
        chartYAxisVo.setName(classifyName);

        List<BigDecimal> dataValueList = new ArrayList<>();

        xAxisList.forEach((d) -> dataValueList.add(BigDecimal.ZERO));

        chartYAxisVo.setData(dataValueList);
        ChartVo chartVo = new ChartVo();
        chartVo.setXAxisList(xAxisList);
        chartVo.setYAxisList(List.of(chartYAxisVo));
        return chartVo;
    }

    private boolean checkIsNeedReturnEmpty(String queryType, Integer dataObtainType) {
        return switch (queryType) {
            case DateType.DAY -> dataObtainType == PointDataType.AUTO;
            case DateType.WEEK -> dataObtainType != PointDataType.HAND_MONTH;
            case DateType.MONTH -> dataObtainType != PointDataType.HAND_MONTH;
            case DateType.YEAR -> true;
            case DateType.CUSTOM -> dataObtainType != PointDataType.HAND_MONTH;
            default -> false;
        };
    }

    @Override
    public ChartVo budget(BudgetQueryParam budgetQueryParam) {
        // 查看预算费用
        BudgetDefEntity entity = budgetDefService.get(budgetQueryParam);
        AssertUtil.nonNull(entity, "当年未找到预算费用");

        List<BudgetValueEntity> budgetValueEntities = budgetValueService.getByBudgetDefIds(Arrays.asList(entity.getId()));
        Map<Integer, List<BudgetValueEntity>> monthBudgetMap = budgetValueEntities.stream().collect(Collectors.groupingBy(BudgetValueEntity::getBudgetMonth));

        //根据查询条件计算起止时间
        String queryType = DateType.YEAR;
        // 获取年开始实际和结束时间
        DateDto dateDto = DateUtils.dateQueryConvert(queryType, budgetQueryParam.getYear(), null, false);
        String classifyId = budgetQueryParam.getClassifyId();
        Classify classify = classifyService.getById(classifyId);
        //构建x轴
        List<LocalDateTime> list = DateUtils.dateToList(queryType, dateDto.getStartDay(), dateDto.getEndDay(), true);
        //判断是否需要返回空值
        ChartVo chartVo = buildEmpty(queryType, list, classify.getClassifyName());

        List<ClassifyDeviceProperty> devicePropertyList = getClassifyDeviceProperties(classifyId);

        List<DeviceMeasureDateDTO> dateDtos = classifySum(classify.getClassifyId(), queryType, dateDto.getStartDay(), dateDto.getEndDay(), classify, devicePropertyList);

        //按照查询类型和数据类型对数据时间进行处理，并分组，将数据处理为x轴需要的格式进行匹配
        Map<String, List<DeviceMeasureDateDTO>> map = buildDataByDataType(dateDtos);
        ChartYAxisVo chartYAxisVo = new ChartYAxisVo();
        chartYAxisVo.setName("实际费用");
        ChartYAxisVo chartYAxisVo1 = new ChartYAxisVo();
        chartYAxisVo1.setName("预算费用");

        List<BigDecimal> yValueList = new ArrayList<>();
        List<BigDecimal> yValueList1 = new ArrayList<>();
        for (String dateTimeStr : chartVo.getXAxisList()) {
            setYVal(map, yValueList, dateTimeStr, EnergyDataTypeEnum.CODE.getCode());
            setMonthYVal(dateTimeStr, monthBudgetMap, yValueList1);
        }
        chartYAxisVo.setData(yValueList);
        chartYAxisVo1.setData(yValueList1);
        List<ChartYAxisVo> chartYAxisVo2 = List.of(chartYAxisVo, chartYAxisVo1);
        chartVo.setYAxisList(chartYAxisVo2);
        return chartVo;
    }

    @Override
    public ChartCodeVo compareDataAndCode(DataQueryDto dataQueryDto) {
        //根据查询条件计算起止时间
        String queryType = dataQueryDto.getQueryType();
        DateDto dateDto = DateUtils.dateQueryConvert(queryType, dataQueryDto.getStartDay(), dataQueryDto.getEndDay(), false);
        //构建x轴
        List<LocalDateTime> list = DateUtils.dateToList(queryType, dateDto.getStartDay(), dateDto.getEndDay());
//        ChartCodeVo chartVo = new ChartCodeVo();
        List<String> xAxisList = DateUtils.xAxisConvert(queryType, list);
        List<ChartYAxisVo> chartYList = new ArrayList<>();
        List<ChartYAxisVo> chartCodeList = new ArrayList<>();
        List<String> queryIdList = dataQueryDto.getClassifyIdList();


        for (String classifyId : queryIdList) {
            Classify classify = classifyService.getById(classifyId);
            List<ClassifyDeviceProperty> devicePropertyList = getClassifyDeviceProperties(classifyId);

            //判断是否需要返回空值
            if (CollectionUtil.isEmpty(devicePropertyList)) {
                chartYList.add(buildEmptyChartYAxisVo(list.size(), classify, "bar"));
                continue;
            }
            Set<String> deviceIdSet = devicePropertyList.stream().map(ClassifyDeviceProperty::getDeviceId).collect(Collectors.toSet());
            ClassifyDeviceProperty classifyDeviceProperty = devicePropertyList.get(0);
            String dataTypeId = classifyDeviceProperty.getDataTypeId();
            Integer calculateType = classifyDeviceProperty.getCalculateType();

            List<DeviceMeasureDateDTO> dateDtos = getDeviceMeasureDateTypeDtos(queryType, dateDto.getStartDay(), dateDto.getEndDay(),
                    classify, deviceIdSet, dataTypeId, calculateType);

            //根据点位数据时间进行分组汇总数据
            if (CollectionUtil.isEmpty(dateDtos)) {
                chartYList.add(buildEmptyChartYAxisVo(list.size(), classify, "bar"));
                continue;
            }

//            multipleProcess(dateDtos, classifyDeviceProperty.getMultiple());

            //按照查询类型和数据类型对数据时间进行处理，并分组，将数据处理为x轴需要的格式进行匹配
            Map<String, List<DeviceMeasureDateDTO>> thisMap = buildDataByDataType(dateDtos);
            List<BigDecimal> yValueList = new ArrayList<>();
            for (String dateTimeStr : xAxisList) {
                //本周期数据
                setYVal(thisMap, yValueList, dateTimeStr, EnergyDataTypeEnum.ENERGY.getCode());
            }
            ChartYAxisVo chartYAxisVo = new ChartYAxisVo();
            chartYAxisVo.setName(classify.getClassifyName());
            chartYAxisVo.setData(yValueList);

            // 费用
            List<BigDecimal> codeValueList = new ArrayList<>();
            for (String dateTimeStr : xAxisList) {
                //本周期数据
                setYVal(thisMap, codeValueList, dateTimeStr, EnergyDataTypeEnum.CODE.getCode());
            }
            ChartYAxisVo chartCodeYAxisVo = new ChartYAxisVo();
            chartCodeYAxisVo.setName(classify.getClassifyName());
            chartCodeYAxisVo.setData(codeValueList);


            chartYAxisVo.setStack(classifyId);
            chartYList.add(chartYAxisVo);
            chartCodeList.add(chartCodeYAxisVo);

        }
        ChartCodeVo chartCodeVo = ChartCodeVo.builder()
                .xAxisList(xAxisList)
                .yAxisList(chartYList)
                .codeyAxisList(chartCodeList)
                .build();

        return chartCodeVo;
    }

    private void setMonthYVal(String dateTimeStr, Map<Integer, List<BudgetValueEntity>> monthBudgetMap, List<BigDecimal> yValueList1) {
        List<BudgetValueEntity> budgetValueEntities = monthBudgetMap.get(Integer.valueOf(dateTimeStr.split("-")[1]));
        yValueList1.add(CollectionUtil.isEmpty(budgetValueEntities) ? BigDecimal.ZERO : budgetValueEntities.get(0).getBudgetVal());
    }
}
